Commit f4381606 authored by Simon's avatar Simon

Teams, manager, banner update

parent 24ee767f
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
## Production ## Production
- build CSS & JS assets - `C:\web\dev.biuro\ npm run build` - build CSS & JS assets - `C:\web\dev.biuro\ npm run build`
- build new image `docker build -t biuro/web:1.21.3 .` (update version number) - build new image `docker build -t biuro/web:1.22.0 .` (update version number)
- login to biuro docker account `docker login --username=biuro --password=9Ndtjd2vKsLvGuFOeFq1KdJs` - login to biuro docker account `docker login --username=biuro --password=9Ndtjd2vKsLvGuFOeFq1KdJs`
- push image to docker repository - `docker push biuro/web:1.21.3` - push image to docker repository - `docker push biuro/web:1.22.0`
## Production ## Production
- update biuro/web image version in .env file (staging or www) - update biuro/web image version in .env file (staging or www)
......
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIGpzCCBY+gAwIBAgISBEA0nQDRLCAARy0oQAx4z591MA0GCSqGSIb3DQEBCwUA MIIGpTCCBY2gAwIBAgISA79ZasTpnugcegvspzV2yz+JMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA5MDUxOTQ2MTRaFw0y ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDExMTkwODQzNDVaFw0y
MDEyMDQxOTQ2MTRaMBsxGTAXBgNVBAMTEHN0YWdpbmcuYml1cm8ubHQwggIiMA0G MTAyMTcwODQzNDVaMBsxGTAXBgNVBAMTEHN0YWdpbmcuYml1cm8ubHQwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCespRWAN7I7Tnl1LMhiHAQM8vko6FQ CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDFpvgebWmUcOrHCCipCUsgCUuz7VzN
OX+HntKdQeGxcfsPxwJ0lqjaqARWgZw+5AXHCYHmE9OkystGMAzR5Sk0FJZ6BFko 3OK4blESc0VoPcPCddMT2/SGO2/YH20h0cd//zL42B23KucOhjQFMvyiwz0WQQ5H
3Z8x56e3vk9vlhds+lRXRyRhy/2JDUKTSME4+kAnOz6pKkA9CaY6eb7vNBCd/4U4 0KRVV53RWLPV7Nw82qMtBP6KjN7HlRSEE+UK1DNppzHm+8hKf46EOO6/8OMC0r5g
2y+KRDlKF/b1JEnu5Dz02KmZs9InCWQV1cF05Cxk3WKAYykwCoYP/XzYj0SGDYHX WRPLJ7gFVboldgI9SX7N8yGLvv0+mafK+ZjYDpJvxAme64IE6T43lX7o7a8rzRik
ZYY2YMbzIxTmjcDOIUUxQ+YRwxX59bSOe1m2tJ9W3jwiGs3WjrwPGloTtb9AhqLr daAM7wJrl0zocqPYj8z78JsWgWBOZTyH5qqMCcjlbHUnFpMjlQ7Z4QBnaFRGruaU
v95XXyCU/ch7dboUYiOXqzY3/0KiI7r4UCAX751SJhdghtHHftmSm/D1eVwAPQDV 3FwnOz9BJFPu+4GMm425/oMc1br/1h0XQLs+S1HySfPW0QORnCYr+mvXNdZobc10
oUFMSby064SobSgBkCaQq/CPCHy19uq40kKvhhSgXMVzVg/4gD/snJeunvlctKUx XTVAmITrXkdQtNNLS7QdDPg5PJPKC2wx6q3/Hi4TyHNC28ceGltchlwRKvev5Jkn
PIPUP+eKTX7cdrwUSSZcxplaClSISFNtRcPFEXW3/pFtXzHfqQ9hSgxwu2LH4WWr GFwpB3olk/qD7ItfQqiYJ/RCo/P9Yb4u/a9jeQUFHsy9dGLavlxoiQ+9S18HLMh2
shytw8o61auD6zWJ8AsaQ6wd0JkqCIaPhaaXud4xD67Pyrf6xvLsypYqUtIW5Pgp hckEGW+mDmalgksb1Mz5vNaA7f0eWsn6UFBHew9WKHORbngktljamwgd+SVL1Pdy
Yk9pxsrXmTbkDY7ZmI2Qa1p+l9tc3f0KKduAh051CUKy1/daFKE7zPhmXaVBCcnC UBuyj0EKlKa5aWU1ZKsahCmqIa6TI9wSNHUGRZH/B/5mJokadiiTd0sULhM6D9Jy
6N/1eNp2n+I1jLwjecX/AA1jxBRcd5/UxGgf9PznQ+Xa952QyvGaBzxlDkR9m5+i +0dGLL4eX2dRP5AtpqfhBMV4JPMsmwFopaUxAX9KgKKiVDgcy44Gwz3+BXJfTuIm
I//wrpIsN9pw2wIDAQABo4ICtDCCArAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW skshtwXr7+sQAwIDAQABo4ICsjCCAq4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQI MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTe
ZKTMA5KJc7oi4TFJG/0Z2MPjfTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv KzQwqGrSrDVyxxLpQnnrXvE2UzAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv
86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmlu 86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmlu
dC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0Lmlu dC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0Lmlu
dC14My5sZXRzZW5jcnlwdC5vcmcvMGkGA1UdEQRiMGCCDGRldi5iaXVyby5lZYIM dC14My5sZXRzZW5jcnlwdC5vcmcvMGkGA1UdEQRiMGCCDGRldi5iaXVyby5lZYIM
ZGV2LmJpdXJvLmx0ggxkZXYuYml1cm8ubHaCEHN0YWdpbmcuYml1cm8uZWWCEHN0 ZGV2LmJpdXJvLmx0ggxkZXYuYml1cm8ubHaCEHN0YWdpbmcuYml1cm8uZWWCEHN0
YWdpbmcuYml1cm8ubHSCEHN0YWdpbmcuYml1cm8ubHYwTAYDVR0gBEUwQzAIBgZn YWdpbmcuYml1cm8ubHSCEHN0YWdpbmcuYml1cm8ubHYwTAYDVR0gBEUwQzAIBgZn
gQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5s gQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5s
ZXRzZW5jcnlwdC5vcmcwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdgDwlaRZ8gDR ZXRzZW5jcnlwdC5vcmcwggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdQBc3EOS/uar
gkAQLS+TiI6tS/4dR+OZ4dA0prCoqo6ycwAAAXRgBQHBAAAEAwBHMEUCIQDTixbk RUSxXprUVuYQN/vV+kfcoXOUsl7m9scOygAAAXXf42yUAAAEAwBGMEQCIBrsCh0m
LSYMitYHci8fgJh8lgy2jG1S4Tglgf0Bx8oHxAIgRbcDLAl1OGoz3Z1OTE14KrT7 bdKDvttT/yUreoCLw+JCF7yMyYJClWxPVnH1AiBEbhKH/NOUl32vttAoeaups8ri
eVKgnPng+iGU+tEKDyEAdwCyHgXMi6LNiiBOh2b5K7mKJSBna9r6cOeySVMt74uQ m+ZTOLefO018Idum+gB2APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTj
XgAAAXRgBQGpAAAEAwBIMEYCIQCcci/k2QnqbgDSk3zLqjRBJ/uaP46mubk7/xMU AAABdd/jbJIAAAQDAEcwRQIgEgL2jXO1eoxSh2HyvvuPpbXsjzPWJtYOB8Lx4cPN
9AfSXgIhAJxnJmQTs4lK6Mzbzmy6gJFqTgQh8amf6DlNC8VZSml5MA0GCSqGSIb3 VjYCIQCoOrc6uknDByywNWzPofwT0aIUbh/MCEet4xeBG736gzANBgkqhkiG9w0B
DQEBCwUAA4IBAQACbWBLFjhbNZzWJWL22Pu4r+vDwsbtI4yhpTm+5SSJ41fG66js AQsFAAOCAQEAEkLYTaQbDNt4kwMWiqxlpSLDJO1IUlwD/V4b7bnMRktmoZFjIt0S
ZTT3SVDx6UMBW3jqM5DCsPtKkCDWV7DkHiitEqH20bisRcqAricszEdzDFHnTvT7 wyiqQJ13nCryjJEVFwkSD+iN2xyxP82MpPdKLbdwa1knHKAujwmIEP5Gdt8zd7e+
m4o0xu75P8RqpU7NJWhVW0vz6gx2wDq3Eed7GFx8Zi+Om0REtukD1Y4kejFpU0o9 YD8b3YqtkYQcXeEMgHrUidAjSiY622PAtiAqfqt/qM4mpiGY0AOJLg0qgb3ffCSa
fAXAtxeGksCi7Wjn6Q6MjK5zBDmwOQ7JyWqLzow3+lt5kNLlTAiDWbvt3EdCZpzK c5XuLboVrkoNcoG0ScXTXYlugAtxn0770BeDdiLCwmfbQ4x8Y7HRvjpQG2e9lNcs
kCEgEzdKoeQPIko4TXiMwjPi4QLDNLOFAUpXF6anqdRzgYISlmqyulRXs2B389B8 l3ULnvfeVohmGTUlzANYh36PLMoTGN0mBvSNs3Z0lFPuse2q6k+YgRIMRc7Oozd1
pMcrgLny/ReJqDwV/7+sGUvz1WHffCCLQ2yQ KbZysJkH2sLUYaVKpDEnZYmvvX+kgHcsZA==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIGpzCCBY+gAwIBAgISBEA0nQDRLCAARy0oQAx4z591MA0GCSqGSIb3DQEBCwUA MIIGpTCCBY2gAwIBAgISA79ZasTpnugcegvspzV2yz+JMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA5MDUxOTQ2MTRaFw0y ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDExMTkwODQzNDVaFw0y
MDEyMDQxOTQ2MTRaMBsxGTAXBgNVBAMTEHN0YWdpbmcuYml1cm8ubHQwggIiMA0G MTAyMTcwODQzNDVaMBsxGTAXBgNVBAMTEHN0YWdpbmcuYml1cm8ubHQwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCespRWAN7I7Tnl1LMhiHAQM8vko6FQ CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDFpvgebWmUcOrHCCipCUsgCUuz7VzN
OX+HntKdQeGxcfsPxwJ0lqjaqARWgZw+5AXHCYHmE9OkystGMAzR5Sk0FJZ6BFko 3OK4blESc0VoPcPCddMT2/SGO2/YH20h0cd//zL42B23KucOhjQFMvyiwz0WQQ5H
3Z8x56e3vk9vlhds+lRXRyRhy/2JDUKTSME4+kAnOz6pKkA9CaY6eb7vNBCd/4U4 0KRVV53RWLPV7Nw82qMtBP6KjN7HlRSEE+UK1DNppzHm+8hKf46EOO6/8OMC0r5g
2y+KRDlKF/b1JEnu5Dz02KmZs9InCWQV1cF05Cxk3WKAYykwCoYP/XzYj0SGDYHX WRPLJ7gFVboldgI9SX7N8yGLvv0+mafK+ZjYDpJvxAme64IE6T43lX7o7a8rzRik
ZYY2YMbzIxTmjcDOIUUxQ+YRwxX59bSOe1m2tJ9W3jwiGs3WjrwPGloTtb9AhqLr daAM7wJrl0zocqPYj8z78JsWgWBOZTyH5qqMCcjlbHUnFpMjlQ7Z4QBnaFRGruaU
v95XXyCU/ch7dboUYiOXqzY3/0KiI7r4UCAX751SJhdghtHHftmSm/D1eVwAPQDV 3FwnOz9BJFPu+4GMm425/oMc1br/1h0XQLs+S1HySfPW0QORnCYr+mvXNdZobc10
oUFMSby064SobSgBkCaQq/CPCHy19uq40kKvhhSgXMVzVg/4gD/snJeunvlctKUx XTVAmITrXkdQtNNLS7QdDPg5PJPKC2wx6q3/Hi4TyHNC28ceGltchlwRKvev5Jkn
PIPUP+eKTX7cdrwUSSZcxplaClSISFNtRcPFEXW3/pFtXzHfqQ9hSgxwu2LH4WWr GFwpB3olk/qD7ItfQqiYJ/RCo/P9Yb4u/a9jeQUFHsy9dGLavlxoiQ+9S18HLMh2
shytw8o61auD6zWJ8AsaQ6wd0JkqCIaPhaaXud4xD67Pyrf6xvLsypYqUtIW5Pgp hckEGW+mDmalgksb1Mz5vNaA7f0eWsn6UFBHew9WKHORbngktljamwgd+SVL1Pdy
Yk9pxsrXmTbkDY7ZmI2Qa1p+l9tc3f0KKduAh051CUKy1/daFKE7zPhmXaVBCcnC UBuyj0EKlKa5aWU1ZKsahCmqIa6TI9wSNHUGRZH/B/5mJokadiiTd0sULhM6D9Jy
6N/1eNp2n+I1jLwjecX/AA1jxBRcd5/UxGgf9PznQ+Xa952QyvGaBzxlDkR9m5+i +0dGLL4eX2dRP5AtpqfhBMV4JPMsmwFopaUxAX9KgKKiVDgcy44Gwz3+BXJfTuIm
I//wrpIsN9pw2wIDAQABo4ICtDCCArAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW skshtwXr7+sQAwIDAQABo4ICsjCCAq4wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQI MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTe
ZKTMA5KJc7oi4TFJG/0Z2MPjfTAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv KzQwqGrSrDVyxxLpQnnrXvE2UzAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv
86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmlu 86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmlu
dC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0Lmlu dC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0Lmlu
dC14My5sZXRzZW5jcnlwdC5vcmcvMGkGA1UdEQRiMGCCDGRldi5iaXVyby5lZYIM dC14My5sZXRzZW5jcnlwdC5vcmcvMGkGA1UdEQRiMGCCDGRldi5iaXVyby5lZYIM
ZGV2LmJpdXJvLmx0ggxkZXYuYml1cm8ubHaCEHN0YWdpbmcuYml1cm8uZWWCEHN0 ZGV2LmJpdXJvLmx0ggxkZXYuYml1cm8ubHaCEHN0YWdpbmcuYml1cm8uZWWCEHN0
YWdpbmcuYml1cm8ubHSCEHN0YWdpbmcuYml1cm8ubHYwTAYDVR0gBEUwQzAIBgZn YWdpbmcuYml1cm8ubHSCEHN0YWdpbmcuYml1cm8ubHYwTAYDVR0gBEUwQzAIBgZn
gQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5s gQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5s
ZXRzZW5jcnlwdC5vcmcwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdgDwlaRZ8gDR ZXRzZW5jcnlwdC5vcmcwggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdQBc3EOS/uar
gkAQLS+TiI6tS/4dR+OZ4dA0prCoqo6ycwAAAXRgBQHBAAAEAwBHMEUCIQDTixbk RUSxXprUVuYQN/vV+kfcoXOUsl7m9scOygAAAXXf42yUAAAEAwBGMEQCIBrsCh0m
LSYMitYHci8fgJh8lgy2jG1S4Tglgf0Bx8oHxAIgRbcDLAl1OGoz3Z1OTE14KrT7 bdKDvttT/yUreoCLw+JCF7yMyYJClWxPVnH1AiBEbhKH/NOUl32vttAoeaups8ri
eVKgnPng+iGU+tEKDyEAdwCyHgXMi6LNiiBOh2b5K7mKJSBna9r6cOeySVMt74uQ m+ZTOLefO018Idum+gB2APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTj
XgAAAXRgBQGpAAAEAwBIMEYCIQCcci/k2QnqbgDSk3zLqjRBJ/uaP46mubk7/xMU AAABdd/jbJIAAAQDAEcwRQIgEgL2jXO1eoxSh2HyvvuPpbXsjzPWJtYOB8Lx4cPN
9AfSXgIhAJxnJmQTs4lK6Mzbzmy6gJFqTgQh8amf6DlNC8VZSml5MA0GCSqGSIb3 VjYCIQCoOrc6uknDByywNWzPofwT0aIUbh/MCEet4xeBG736gzANBgkqhkiG9w0B
DQEBCwUAA4IBAQACbWBLFjhbNZzWJWL22Pu4r+vDwsbtI4yhpTm+5SSJ41fG66js AQsFAAOCAQEAEkLYTaQbDNt4kwMWiqxlpSLDJO1IUlwD/V4b7bnMRktmoZFjIt0S
ZTT3SVDx6UMBW3jqM5DCsPtKkCDWV7DkHiitEqH20bisRcqAricszEdzDFHnTvT7 wyiqQJ13nCryjJEVFwkSD+iN2xyxP82MpPdKLbdwa1knHKAujwmIEP5Gdt8zd7e+
m4o0xu75P8RqpU7NJWhVW0vz6gx2wDq3Eed7GFx8Zi+Om0REtukD1Y4kejFpU0o9 YD8b3YqtkYQcXeEMgHrUidAjSiY622PAtiAqfqt/qM4mpiGY0AOJLg0qgb3ffCSa
fAXAtxeGksCi7Wjn6Q6MjK5zBDmwOQ7JyWqLzow3+lt5kNLlTAiDWbvt3EdCZpzK c5XuLboVrkoNcoG0ScXTXYlugAtxn0770BeDdiLCwmfbQ4x8Y7HRvjpQG2e9lNcs
kCEgEzdKoeQPIko4TXiMwjPi4QLDNLOFAUpXF6anqdRzgYISlmqyulRXs2B389B8 l3ULnvfeVohmGTUlzANYh36PLMoTGN0mBvSNs3Z0lFPuse2q6k+YgRIMRc7Oozd1
pMcrgLny/ReJqDwV/7+sGUvz1WHffCCLQ2yQ KbZysJkH2sLUYaVKpDEnZYmvvX+kgHcsZA==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
......
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCespRWAN7I7Tnl MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDFpvgebWmUcOrH
1LMhiHAQM8vko6FQOX+HntKdQeGxcfsPxwJ0lqjaqARWgZw+5AXHCYHmE9OkystG CCipCUsgCUuz7VzN3OK4blESc0VoPcPCddMT2/SGO2/YH20h0cd//zL42B23KucO
MAzR5Sk0FJZ6BFko3Z8x56e3vk9vlhds+lRXRyRhy/2JDUKTSME4+kAnOz6pKkA9 hjQFMvyiwz0WQQ5H0KRVV53RWLPV7Nw82qMtBP6KjN7HlRSEE+UK1DNppzHm+8hK
CaY6eb7vNBCd/4U42y+KRDlKF/b1JEnu5Dz02KmZs9InCWQV1cF05Cxk3WKAYykw f46EOO6/8OMC0r5gWRPLJ7gFVboldgI9SX7N8yGLvv0+mafK+ZjYDpJvxAme64IE
CoYP/XzYj0SGDYHXZYY2YMbzIxTmjcDOIUUxQ+YRwxX59bSOe1m2tJ9W3jwiGs3W 6T43lX7o7a8rzRikdaAM7wJrl0zocqPYj8z78JsWgWBOZTyH5qqMCcjlbHUnFpMj
jrwPGloTtb9AhqLrv95XXyCU/ch7dboUYiOXqzY3/0KiI7r4UCAX751SJhdghtHH lQ7Z4QBnaFRGruaU3FwnOz9BJFPu+4GMm425/oMc1br/1h0XQLs+S1HySfPW0QOR
ftmSm/D1eVwAPQDVoUFMSby064SobSgBkCaQq/CPCHy19uq40kKvhhSgXMVzVg/4 nCYr+mvXNdZobc10XTVAmITrXkdQtNNLS7QdDPg5PJPKC2wx6q3/Hi4TyHNC28ce
gD/snJeunvlctKUxPIPUP+eKTX7cdrwUSSZcxplaClSISFNtRcPFEXW3/pFtXzHf GltchlwRKvev5JknGFwpB3olk/qD7ItfQqiYJ/RCo/P9Yb4u/a9jeQUFHsy9dGLa
qQ9hSgxwu2LH4WWrshytw8o61auD6zWJ8AsaQ6wd0JkqCIaPhaaXud4xD67Pyrf6 vlxoiQ+9S18HLMh2hckEGW+mDmalgksb1Mz5vNaA7f0eWsn6UFBHew9WKHORbngk
xvLsypYqUtIW5PgpYk9pxsrXmTbkDY7ZmI2Qa1p+l9tc3f0KKduAh051CUKy1/da tljamwgd+SVL1PdyUBuyj0EKlKa5aWU1ZKsahCmqIa6TI9wSNHUGRZH/B/5mJoka
FKE7zPhmXaVBCcnC6N/1eNp2n+I1jLwjecX/AA1jxBRcd5/UxGgf9PznQ+Xa952Q diiTd0sULhM6D9Jy+0dGLL4eX2dRP5AtpqfhBMV4JPMsmwFopaUxAX9KgKKiVDgc
yvGaBzxlDkR9m5+iI//wrpIsN9pw2wIDAQABAoICAQCZMEzcEA796XDAGGep8Ogr y44Gwz3+BXJfTuImskshtwXr7+sQAwIDAQABAoICAD9sktYAug5+JXh0r8d+SfMf
27PvyrwGkto18evgfR39iccN3c7S+DOajiFR198ZHkctcFIB5BWit1ctM2jMm+cA yIEWO997b+1KyQ0onC8VEspF0NPgkxi33e32N6jQjjoOhCbCAtcSF07b1bmNYPBB
LPdsZRIjznrDU5ikV4Kadkm6mpIbhcLq3FyqlTA0uEA8XeTbeebsqKpFwTDCtY7H wkpv2ctFslYIZYYV9q9A8HM+nXoGzj9bcOmOdyTi1W6iJVVT53l9dgoh4HOhaUuC
nHyF54eT8JCdaWnbyfJLhHIRtiPZPePJSLmNkRUZtrL9wNvRqZpR0GaLxzzN5qVC WvY+9gQo0WcxeaWMms0GjzVnbh9cU3lqcg0ydVt2uIssMeVXfNbYL8Kvrd1cRXst
7lj5BcTWRVwe1aB2RuEABMmesKL4AVDuyGBIXxOhjhR1tzkwQ2nMig80E6gY9BkL OjbN+4hajl9YGui3hmBY2SbXDioSTVHtdh/x8HiTlkqVoTetk/JVFiYm4LsdrmmA
eZ9aDBzscNORh3QOHkQOWP/8eRdeapj1yONrXA45cC7qrBQyni5msP2DE0G2se0P WvrLiQZfp9qW8ndO1vgrEKk0CUiT2TLZisYpyO/7P5p/xO4AuRRHweNpvf4Cv7Og
oqn/AyJfF4MzGGg6gU8L7mSgViMwdHOx33QyBqp7gVh3DvUhK9HmKY1/fc9fMn8e rR0LrM4SUqXt4BAs2Yfs/+HuNyuvCCkKRxiwyaz4fPwSppG7hv/pV3gp5TbdZJEz
pckWatTdlAR/3HeV4SNY9v8RP52+9IG9FUbpogzeqcif8iSuhbBAfUyYAAcCH5st sKJ8uveXf0+tNDjpMT8lrE79AT3ZwVi3pO0cHaayonD3ynphk8sOtAWbJ0mgstMl
3AxzipnSTblW9+Y2y9wqkNTE5HixO5RgHcTgXXDuKxKl0tBlgspatXe/4fqucWTu 0I5EqxXFvxAko2uqmn2aRBcrVTOvKrJRnB5KrZIfgcxgHJyWwxI6bHy5Q0NCCedZ
feHkd3dtXIWGlZlLJJRSL7X4iUNusl23pX+KqvmZNd/+wEEzq0fQHJCBtourIrKw VfLNCKRzKprxXxnCodxa5o7CLJlKsLx5Qbr85tzGkdknD+l3iGx1udhFXZmHN+kW
7RWnFBiD+sH59rAA/3WLwwEIq25c7ZGeRyjG5TCY6WM/8lRZ/uI/CDFwmRoCgrjj t2oYnIMPaMX2rzhqYcz2RDx8MCxiVe3lWMbkIDAjhuuMcJu1Jq9Uk7uIJcngzOUd
rRW12cTLsznQzu99p782oQKCAQEAyg2uXhU6kGRqx6nHH6NLzxtPTtum2al2mwi1 2wNosVCWtVi2tzxlAT2xAoIBAQDzXvJdi/3/FDVngiFIWGJAjABfaXF3lTF7IZaS
uGsKiYI+C+5yG3c8JpX7eng4BYQkGnV9XEkQcHG329ac1u9Fp6d46rUcTf03JXAr 4HKfa0M2QcAt1G/MVkE6bK1aGiD6QPHtXfLo8zTAGPpHEz3ViP49mXE3Ao71qOnD
YrT0cXIYoKnt/3paDFyZ9mF4x1Py8C26uL77Y4TT3MBQCOzut5B5IwqHsJUC8Dzr a3JdTNWBHfa/JI8Fo8X9ddB3guoY9DbJBr4mCIrvZ3RPJbxLjxpilR2UD7UsjsZG
LGeWZeEU5N+i+7JbJirvNhUvbSJMI6qx8dtaOwMj/IatbBfoNupFnDzQQPs4V6H/ xw4Qd2wZn+QSoG1sdv+fAnq6iu7Afa7CSb5TJVEJlEeMgUvuYRVAbNWnh5UK2159
z/2Hf9cXimGmXPjCHCqZj5KJ52mjlI8iNchd5LapPlGJG4FMHlSjWiNYQL8M8/2d gq2K6yU3FyT5UAcYJ9oXB/wZKc1BZL6PZns+VVGpcidIFQdG3eJfKTQrEAK1SfIG
ST3+HowkFISxBfuGR88F+laFpBvWO4hlJeb6hfpq8yvHj0ADGQKCAQEAyRGIOqT9 nB7s69XGcHEu6cw2nwgkSOUYNEzVdVsfSfAHDRxLaAIEMJDdAoIBAQDP6KydGaKX
lAveR8vwSoCRlRaI61n9JEEhG2cYHa+0tgMCXb+3+bMVMAc6l2Ajn3362W5usckz SP4isghT5d2AuMJESikDNt2O81JFK8cO9KxgpeNwo4F43gl8EmpKSIdge6bYOIvT
QSPw5LhJv5cRIUrY7pzllxQW0qZS5+hL4m230ybWFhzOCdXCvMJwvjvVAKNbZIlG ZRGiUFH4IMy2iDOr0+IT/PGtsF8zXHcjmNO3oqpoWK7zM2c/ll0mpxisUneC4QYm
HcaSNwMfwyAts0NW/03O8QwZa0Upr7lObYEu/tPvKSq8PK/8mCXbjYeNJHYHFfqg YdEU9Briv5Tk0DIMUzA43V7/XMRu6/Rkan9HtrkDZhs/1cU4Dw7o+L+tKOPcE6vP
srGc3qdizDSjbURjTJwEzDiIF9/A5mNlwcQpqi/oze1CD9i0an1Q1w4cYzrELxTP ZdxZUMrmHWffJAwrNs0clxaMzdi2AW82CGKdpZKoIuqhhkH2tUls9rEdap6oPqOf
Z+2Mx0DwXj2YgP3PoWpvBFTvkCna3EkYxTp30+x4oFyRhcKTvVdZIQPl170o+v3S fQD12vxOV1YrB55FLIY09FeSfgLwC71SF5AeTaLJZyxoTa3jwRPbTpGHPlJddDbd
jWI3EeiID9imEwKCAQBtUMOS0UdzEXEX/wnlWxLLxUm+L2ZxApdRv3+ZfAgiZ12s B+5W5hxpbqZfAoIBAQCvv44ozfKzpQVX5Vphoyn40OFoBX5iTAQ6livlj15XD5+u
VOBVbcgUVDbPhrVAfsKNsh0Vzc3gGBZSESWfv6pez2PDECN1KlcooSxH5gEOU51x 69Z7giDmIBfkuByLp7jO392Ve7XyUcdzPdZnQ1bxAIgRNeDTR+6zKrL9Y3doNxcr
Zx6Fhyuq3nrJ6uhOZ2Pbf9Iy29jkedup5j4m5hEtLTPsumi5J5WEZmESECU1j3Yf sdbBfAYonXdaLR1JYOnq8Vkq3MquLpcegcg1a9vJeOMl8+czSBCex9AZxp+6dnND
ccMbC972omnzR7j2AYVSEqrdYEDMBqH0oOS4w6J1+3+XzOsbDQ/pkZL2c4NYrgVl IfsTFHVQ0bKRQrocQj5eFaUBOz3NT3JxB3qP1cNetw8gwjecTsXr3DUlUBxA6MSs
b/ly+X8DgCS+oZiMpAHFgT8P/AyYjh64waI9SFHnYwFR5id8OCEI7KCpHKoc2tM2 PvN9czRcVlMhNKvyBATsx3LxnaE8h2J8iioh3MWvgIZ8EAZTXrGF94tnCJEwqLJt
aqffxbpbpWzliOQa6piYcu3OeM33qIkucPQx038ZAoIBABN8JnaAbK5/I/BTPBsM JkAmD8JgY4H+qgF+9C3ULHaMZtmGTgpzzf0+x0+lAoIBAQDGqh9e0qMRincEcjgQ
MI+BGo2sL9LmmN299OFTmLCWxBDvtlV1XFVGLhBjWbBoFfoiMIn8FIJ4iCyyCzuM 6yH4IRPIq1B7OM8HDKx9WjKQsO2SQJGPDT3nX8uSWgpkxt9NK3qnO4koy3fJMJTS
2TUfurwM6lbktH1/bsNYiJoNxeWpes+zxOfBFlkSgrh8tdyU+BNbFjdmed7o55gS 04ypkoZFV2a9EMNi45hkfKN/SUZtP6szoCI0U9cB5M1H5P1nlDmMvzbgMDHYotSZ
MzuPCAw/rxE++euiTTLhQ09rWHGLej7EDG/ZIiJgcNFbVHs3EOK5Yf9PJQOStwlR /NTqu6JHMqpue+GNg3hUQXU7CqRqw0gQ3l2FZuBYC9OEfESz0tHAdq+Cs2OVmOT4
BJFfMjxHVlOwGsgtf9UTxtWrO9ppQCdMmb1NY9Z6BG6CyI95L2/clWjd5Wmdym1n c/rQNyLFnEzsV9b9XqkIaWB6MhMBbrgvn4WyKJcZhesOir99S2clfw1cldb4FnNm
jLLbZdafqNiDnp+a3sHAN61NSDV6UgpATj3nKEgOAe4oIYrxotoH5PKclPegUCcw 7H9zCImMsdnf+edAHNbzx1P1gHx+6FJ3vvWpCSjy64js0yuuHrgXgrf2BuEQ+jsF
+I8CggEAP6aKIL47N09CqItQzAFwtuHkF5RZWb7GuKQYCUjl9SJ59ia2pRzhyJtC 5+xjAoIBABTq4cx/9cW0LbuFqYVwV/cPIaDFmOOu01U7t6ZUHHmp+W6AQ+s674Ln
hZoOcH+ywMXwAldfDFStYO87aGnD9hc0bprO+mG+HNPYqLbV4UV4gt4/PsZN8oMa WnfVeabyuc0YZxXgRLmRH26S7zAe7GtIiiV048TyAT8LpIxkw7h4sJxSdWBlhxg8
CJkkRU1LrlE1kQEHiLVVPvwm3PMmn8ca2ub2kOTp6W3bNg291G9xD3S7/CvGYJ4T 4PObSvYXhL+4z8IAK5fgn7o6/qFVwhPMnXaYaxpiBzlF1s8R/BSkhRYJh7nQzE8/
AKAz4/4bSbuHSomS/bhfUE4BolXTlLlRu0YfQCdNafN4HsVYzfvLH5BxzF8XG22n rYN/x71VX7/NBbJmnvXArXojwX5Ll8Dfw3M3dJ61t6qBCHzjVhoqYfoWUeO6dWLP
4wiRXAjFaJrYEouL690mIxLDIm7E85QlP2OOjh9yO03Mm3yipQ8TvLMVUkYj3BMR 2q/+GfMCMI4gBV3lw5V8KfeknX1QM0hIA39qEZZ17XMWD9k1Fb7FJgp2phqgaDNG
kcu2i7tDetB+D9wL7ks44rVS2P71Eg== fWE3FAKd2Fvh9cF7nEwcMwnkcI8Wkh8=
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
...@@ -51,7 +51,6 @@ class JsonDataCollector ...@@ -51,7 +51,6 @@ class JsonDataCollector
'member' => [ 'member' => [
'slug' => 'manager_id', 'slug' => 'manager_id',
'name' => 'manager_name', 'name' => 'manager_name',
'position' => 'manager_position',
'__primary' => true, '__primary' => true,
], ],
]; ];
......
...@@ -125,8 +125,8 @@ function getSource($env) ...@@ -125,8 +125,8 @@ function getSource($env)
if ($env === 'dev') { if ($env === 'dev') {
// $inputFile = plugin_dir_path(__FILE__) . "source_data/wp_biuro.php.xml"; // $inputFile = plugin_dir_path(__FILE__) . "source_data/wp_biuro.php.xml";
// $inputFile = "https://base.biuro.lt/_export/wp_biuro.php"; // $inputFile = "https://base.biuro.lt/_export/wp_biuro.php";
$inputFile = "https://base.biuro.lt/_devSkirmantas/lt/jobs/AdvertExport/Biuro.php"; // $inputFile = "https://base.biuro.lt/_devSkirmantas/lt/jobs/AdvertExport/Biuro.php";
// $inputFile = "https://base.biuro.lt/_export/{$script}"; $inputFile = "https://base.biuro.lt/_export/{$script}";
} elseif ($env === 'prod') { } elseif ($env === 'prod') {
// $inputFile = "http://export.biuro.lt/wp_biuro.php"; // $inputFile = "http://export.biuro.lt/wp_biuro.php";
$inputFile = "http://export.biuro.lt/{$script}"; $inputFile = "http://export.biuro.lt/{$script}";
......
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Loco Translate 2.4.4-dev\n" "Project-Id-Version: Loco Translate 2.4.5-dev\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-26 17:18+0000\n" "POT-Creation-Date: 2020-11-19 17:26+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: \n" "Language-Team: \n"
...@@ -13,7 +13,7 @@ msgstr "" ...@@ -13,7 +13,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: Loco https://localise.biz/\n" "X-Generator: Loco https://localise.biz/\n"
"X-Loco-Version: 2.4.4-dev; wp-5.5.1" "X-Loco-Version: 2.4.5-dev; wp-5.5.3"
#: src/fs/FileWriter.php:214 #: src/fs/FileWriter.php:214
#, php-format #, php-format
...@@ -131,7 +131,7 @@ msgid_plural "%s words" ...@@ -131,7 +131,7 @@ msgid_plural "%s words"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: tpl/admin/config/settings.php:148 #: tpl/admin/config/settings.php:165
msgid "About file system access" msgid "About file system access"
msgstr "" msgstr ""
...@@ -204,7 +204,7 @@ msgstr "" ...@@ -204,7 +204,7 @@ msgstr ""
msgid "Allow (with warning)" msgid "Allow (with warning)"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:159 #: tpl/admin/config/settings.php:176
msgid "Allow full access to these roles" msgid "Allow full access to these roles"
msgstr "" msgstr ""
...@@ -436,8 +436,8 @@ msgstr "" ...@@ -436,8 +436,8 @@ msgstr ""
msgid "Disallow" msgid "Disallow"
msgstr "" msgstr ""
#: src/data/Settings.php:171 src/admin/file/EditController.php:162 #: src/data/Settings.php:173 src/admin/file/EditController.php:164
#: src/admin/bundle/LocaleController.php:130 tpl/admin/config/settings.php:177 #: src/admin/bundle/LocaleController.php:130 tpl/admin/config/settings.php:194
#: tpl/admin/config/apis.php:122 tpl/admin/config/prefs.php:45 #: tpl/admin/config/apis.php:122 tpl/admin/config/prefs.php:45
#: tpl/admin/common/inc-fsconn.php:16 tpl/admin/common/inc-fsconn.php:41 #: tpl/admin/common/inc-fsconn.php:16 tpl/admin/common/inc-fsconn.php:41
#: tpl/admin/errors/no-backups.php:22 #: tpl/admin/errors/no-backups.php:22
...@@ -474,7 +474,7 @@ msgstr "" ...@@ -474,7 +474,7 @@ msgstr ""
msgid "Editing %1$s in %2$s" msgid "Editing %1$s in %2$s"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:138 #: tpl/admin/config/settings.php:155
msgid "Editing of POT (template) files" msgid "Editing of POT (template) files"
msgstr "" msgstr ""
...@@ -490,13 +490,13 @@ msgid "%s translation" ...@@ -490,13 +490,13 @@ msgid "%s translation"
msgstr "" msgstr ""
#. button for adding a new string when manually editing a POT file #. button for adding a new string when manually editing a POT file
#: src/admin/file/EditController.php:187 #: src/admin/file/EditController.php:189
msgctxt "Editor" msgctxt "Editor"
msgid "Add" msgid "Add"
msgstr "" msgstr ""
#. Button that opens window for auto-translating #. Button that opens window for auto-translating
#: src/admin/file/EditController.php:198 #: src/admin/file/EditController.php:200
msgctxt "Editor" msgctxt "Editor"
msgid "Auto" msgid "Auto"
msgstr "" msgstr ""
...@@ -520,7 +520,7 @@ msgid "Context not loaded" ...@@ -520,7 +520,7 @@ msgid "Context not loaded"
msgstr "" msgstr ""
#. Button for downloading a PO, MO or POT file #. Button for downloading a PO, MO or POT file
#: src/admin/file/EditController.php:200 #: src/admin/file/EditController.php:202
msgctxt "Editor" msgctxt "Editor"
msgid "Download" msgid "Download"
msgstr "" msgstr ""
...@@ -532,19 +532,19 @@ msgid "Plural" ...@@ -532,19 +532,19 @@ msgid "Plural"
msgstr "" msgstr ""
#. button for removing a string when manually editing a POT file #. button for removing a string when manually editing a POT file
#: src/admin/file/EditController.php:189 #: src/admin/file/EditController.php:191
msgctxt "Editor" msgctxt "Editor"
msgid "Remove" msgid "Remove"
msgstr "" msgstr ""
#. Button that reloads current screen #. Button that reloads current screen
#: src/admin/file/EditController.php:196 #: src/admin/file/EditController.php:198
msgctxt "Editor" msgctxt "Editor"
msgid "Revert" msgid "Revert"
msgstr "" msgstr ""
#. Button that saves translations to disk #. Button that saves translations to disk
#: src/admin/file/EditController.php:192 #: src/admin/file/EditController.php:194
msgctxt "Editor" msgctxt "Editor"
msgid "Save" msgid "Save"
msgstr "" msgstr ""
...@@ -574,13 +574,13 @@ msgid "Suggest translation" ...@@ -574,13 +574,13 @@ msgid "Suggest translation"
msgstr "" msgstr ""
#. Button that runs in-editor sync/operation #. Button that runs in-editor sync/operation
#: src/admin/file/EditController.php:194 #: src/admin/file/EditController.php:196
msgctxt "Editor" msgctxt "Editor"
msgid "Sync" msgid "Sync"
msgstr "" msgstr ""
#. Button that toggles between "code" and regular text editing modes #. Button that toggles between "code" and regular text editing modes
#: src/admin/file/EditController.php:206 #: src/admin/file/EditController.php:208
msgctxt "Editor" msgctxt "Editor"
msgid "Toggle code view" msgid "Toggle code view"
msgstr "" msgstr ""
...@@ -591,7 +591,7 @@ msgid "Toggle Fuzzy" ...@@ -591,7 +591,7 @@ msgid "Toggle Fuzzy"
msgstr "" msgstr ""
#. Button that toggles invisible characters #. Button that toggles invisible characters
#: src/admin/file/EditController.php:204 #: src/admin/file/EditController.php:206
msgctxt "Editor" msgctxt "Editor"
msgid "Toggle invisibles" msgid "Toggle invisibles"
msgstr "" msgstr ""
...@@ -632,7 +632,7 @@ msgstr "" ...@@ -632,7 +632,7 @@ msgstr ""
msgid "Enter a new location for this file" msgid "Enter a new location for this file"
msgstr "" msgstr ""
#: src/js/Strings.php:98 src/error/Exception.php:149 #: src/js/Strings.php:98 src/error/Exception.php:158
msgid "Error" msgid "Error"
msgstr "" msgstr ""
...@@ -691,7 +691,7 @@ msgid "Failed to save file" ...@@ -691,7 +691,7 @@ msgid "Failed to save file"
msgstr "" msgstr ""
#. %s will be replaced with the name of a missing POT file #. %s will be replaced with the name of a missing POT file
#: src/ajax/SyncController.php:42 #: src/ajax/SyncController.php:50
#, php-format #, php-format
msgid "Falling back to source extraction because %s is missing" msgid "Falling back to source extraction because %s is missing"
msgstr "" msgstr ""
...@@ -793,7 +793,7 @@ msgstr "" ...@@ -793,7 +793,7 @@ msgstr ""
msgid "File size" msgid "File size"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:115 tpl/admin/config/settings.php:119 #: tpl/admin/config/settings.php:132 tpl/admin/config/settings.php:136
msgid "File system access" msgid "File system access"
msgstr "" msgstr ""
...@@ -813,7 +813,7 @@ msgid "" ...@@ -813,7 +813,7 @@ msgid ""
msgstr "" msgstr ""
#. Placeholder text for text filter above editor #. Placeholder text for text filter above editor
#: src/admin/file/EditController.php:202 #: src/admin/file/EditController.php:204
msgid "Filter translations" msgid "Filter translations"
msgstr "" msgstr ""
...@@ -844,6 +844,10 @@ msgstr "" ...@@ -844,6 +844,10 @@ msgstr ""
msgid "Full documentation" msgid "Full documentation"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:110
msgid "Fuzzy matching tolerance:"
msgstr ""
#: tpl/admin/config/settings.php:27 #: tpl/admin/config/settings.php:27
msgid "Generate hash tables" msgid "Generate hash tables"
msgstr "" msgstr ""
...@@ -860,15 +864,15 @@ msgstr "" ...@@ -860,15 +864,15 @@ msgstr ""
msgid "Go to WordPress Core" msgid "Go to WordPress Core"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:155 #: tpl/admin/config/settings.php:172
msgid "Grant access to roles" msgid "Grant access to roles"
msgstr "" msgstr ""
#: src/ajax/ApisController.php:26 src/admin/file/EditController.php:190 #: src/ajax/ApisController.php:26 src/admin/file/EditController.php:192
msgid "Help" msgid "Help"
msgstr "" msgstr ""
#: src/mvc/AdminController.php:53 #: src/mvc/AdminController.php:52
msgid "Help & support" msgid "Help & support"
msgstr "" msgstr ""
...@@ -951,7 +955,7 @@ msgid "Just copy English source strings" ...@@ -951,7 +955,7 @@ msgid "Just copy English source strings"
msgstr "" msgstr ""
#. relative time when something happened in the last 30 seconds #. relative time when something happened in the last 30 seconds
#: src/mvc/FileParams.php:145 #: src/mvc/FileParams.php:149
msgid "Just now" msgid "Just now"
msgstr "" msgstr ""
...@@ -1021,13 +1025,6 @@ msgstr "" ...@@ -1021,13 +1025,6 @@ msgstr ""
msgid "Loco interrupted by output from %s:%u" msgid "Loco interrupted by output from %s:%u"
msgstr "" msgstr ""
#: loco.php:140
#, php-format
msgid ""
"Loco requires the \"%s\" PHP extension. Ask your hosting provider to install "
"it"
msgstr ""
#. change "en" in the URL to your language if it's available at http://php.net/docs.php #. change "en" in the URL to your language if it's available at http://php.net/docs.php
#: tpl/admin/errors/no-tokenizer.php:17 #: tpl/admin/errors/no-tokenizer.php:17
msgid "" msgid ""
...@@ -1047,16 +1044,26 @@ msgstr "" ...@@ -1047,16 +1044,26 @@ msgstr ""
msgid "Loco Translate %s" msgid "Loco Translate %s"
msgstr "" msgstr ""
#: src/data/Settings.php:169 #: src/data/Settings.php:171
msgid "" msgid ""
"Loco Translate 2.4 supports third party translation providers. Set up your " "Loco Translate 2.4 supports third party translation providers. Set up your "
"API keys in the plugin settings!" "API keys in the plugin settings!"
msgstr "" msgstr ""
#: src/mvc/AdminController.php:116 #: src/mvc/AdminController.php:115
msgid "Loco Translate is powered by" msgid "Loco Translate is powered by"
msgstr "" msgstr ""
#: loco.php:140
#, php-format
#| msgid ""
#| "Loco requires the \"%s\" PHP extension. Ask your hosting provider "
#| "to install it"
msgid ""
"Loco Translate requires the \"%s\" PHP extension. Ask your hosting provider "
"to install it"
msgstr ""
#. Page title for plugin home screen #. Page title for plugin home screen
#: src/mvc/AdminRouter.php:39 #: src/mvc/AdminRouter.php:39
msgid "Loco, Translation Management" msgid "Loco, Translation Management"
...@@ -1090,7 +1097,7 @@ msgid "MO file exists for this language already. Delete it first" ...@@ -1090,7 +1097,7 @@ msgid "MO file exists for this language already. Delete it first"
msgstr "" msgstr ""
#. @var Loco_mvc_ViewParams $verbose #. @var Loco_mvc_ViewParams $verbose
#: tpl/admin/config/settings.php:130 #: tpl/admin/config/settings.php:147
msgid "Modification of installed files" msgid "Modification of installed files"
msgstr "" msgstr ""
...@@ -1136,11 +1143,11 @@ msgstr "" ...@@ -1136,11 +1143,11 @@ msgstr ""
msgid "New template" msgid "New template"
msgstr "" msgstr ""
#: src/admin/init/InitPotController.php:116 #: src/admin/init/InitPotController.php:105
msgid "New template file" msgid "New template file"
msgstr "" msgstr ""
#: src/admin/init/InitPotController.php:117 #: src/admin/init/InitPotController.php:106
#, php-format #, php-format
msgid "New translations template for \"%s\"" msgid "New translations template for \"%s\""
msgstr "" msgstr ""
...@@ -1175,7 +1182,7 @@ msgstr "" ...@@ -1175,7 +1182,7 @@ msgstr ""
msgid "no wildcards" msgid "no wildcards"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:89 tpl/admin/config/settings.php:125 #: tpl/admin/config/settings.php:89 tpl/admin/config/settings.php:142
msgid "Not recommended" msgid "Not recommended"
msgstr "" msgstr ""
...@@ -1241,7 +1248,7 @@ msgstr[0] "" ...@@ -1241,7 +1248,7 @@ msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#. Where %2$s is the maximum size of a file that will be included and %3$s is the largest encountered #. Where %2$s is the maximum size of a file that will be included and %3$s is the largest encountered
#: src/ajax/SyncController.php:73 #: src/ajax/SyncController.php:80
#, php-format #, php-format
msgid "" msgid ""
"One file has been skipped because it's %3$s. (Max is %2$s). Check all " "One file has been skipped because it's %3$s. (Max is %2$s). Check all "
...@@ -1306,7 +1313,7 @@ msgstr "" ...@@ -1306,7 +1313,7 @@ msgstr ""
msgid "Permission denied to update file" msgid "Permission denied to update file"
msgstr "" msgstr ""
#: src/package/Plugin.php:208 #: src/package/Plugin.php:225
#, php-format #, php-format
msgid "Plugin not found: %s" msgid "Plugin not found: %s"
msgstr "" msgstr ""
...@@ -1400,7 +1407,7 @@ msgstr "" ...@@ -1400,7 +1407,7 @@ msgstr ""
msgid "POT file saved" msgid "POT file saved"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:102 #: tpl/admin/config/settings.php:119
msgid "POT template files" msgid "POT template files"
msgstr "" msgstr ""
...@@ -1468,11 +1475,11 @@ msgstr "" ...@@ -1468,11 +1475,11 @@ msgstr ""
msgid "Save config" msgid "Save config"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:124 #: tpl/admin/config/settings.php:141
msgid "Save credentials in session" msgid "Save credentials in session"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:176 tpl/admin/config/apis.php:121 #: tpl/admin/config/settings.php:193 tpl/admin/config/apis.php:121
#: tpl/admin/config/prefs.php:44 #: tpl/admin/config/prefs.php:44
msgid "Save settings" msgid "Save settings"
msgstr "" msgstr ""
...@@ -1529,8 +1536,8 @@ msgid "Sets" ...@@ -1529,8 +1536,8 @@ msgid "Sets"
msgstr "" msgstr ""
#: src/mvc/AdminRouter.php:67 src/mvc/AdminRouter.php:72 #: src/mvc/AdminRouter.php:67 src/mvc/AdminRouter.php:72
#: src/data/Settings.php:170 tpl/ajax/modal-apis-empty.php:15 #: src/data/Settings.php:172 tpl/ajax/modal-apis-empty.php:15
#: src/admin/file/EditController.php:161 tpl/admin/common/inc-fsconn.php:18 #: src/admin/file/EditController.php:163 tpl/admin/common/inc-fsconn.php:18
#: tpl/admin/common/inc-fsconn.php:43 tpl/admin/errors/no-backups.php:24 #: tpl/admin/common/inc-fsconn.php:43 tpl/admin/errors/no-backups.php:24
msgid "Settings" msgid "Settings"
msgstr "" msgstr ""
...@@ -1613,6 +1620,10 @@ msgstr "" ...@@ -1613,6 +1620,10 @@ msgstr ""
msgid "Support forum" msgid "Support forum"
msgstr "" msgstr ""
#: tpl/admin/config/settings.php:102 tpl/admin/config/settings.php:106
msgid "Syncing PO files"
msgstr ""
#: src/admin/config/DebugController.php:47 #: src/admin/config/DebugController.php:47
msgid "System diagnostics" msgid "System diagnostics"
msgstr "" msgstr ""
...@@ -1623,7 +1634,7 @@ msgstr "" ...@@ -1623,7 +1634,7 @@ msgstr ""
msgid "Template file" msgid "Template file"
msgstr "" msgstr ""
#: src/admin/init/InitPotController.php:68 #: src/admin/init/InitPotController.php:57
msgid "Template file already exists" msgid "Template file already exists"
msgstr "" msgstr ""
...@@ -1785,7 +1796,7 @@ msgid "This information is for developers to find problems in the bundle setup" ...@@ -1785,7 +1796,7 @@ msgid "This information is for developers to find problems in the bundle setup"
msgstr "" msgstr ""
#. Warning when POT file is opened in the file editor. It can be disabled in settings. #. Warning when POT file is opened in the file editor. It can be disabled in settings.
#: src/admin/file/EditController.php:160 #: src/admin/file/EditController.php:162
msgid "" msgid ""
"This is NOT a translation file. Manual editing of source strings is not " "This is NOT a translation file. Manual editing of source strings is not "
"recommended." "recommended."
...@@ -1864,12 +1875,12 @@ msgid "Translation progress %s%%" ...@@ -1864,12 +1875,12 @@ msgid "Translation progress %s%%"
msgstr "" msgstr ""
#. Where %s is the name of the invalid POT file #. Where %s is the name of the invalid POT file
#: src/ajax/SyncController.php:54 src/admin/file/EditController.php:122 #: src/ajax/SyncController.php:62 src/admin/file/EditController.php:124
#, php-format #, php-format
msgid "Translation template is invalid (%s)" msgid "Translation template is invalid (%s)"
msgstr "" msgstr ""
#: src/admin/file/EditController.php:117 #: src/admin/file/EditController.php:119
#, php-format #, php-format
msgid "Translations don't match template. Run sync to update from %s" msgid "Translations don't match template. Run sync to update from %s"
msgstr "" msgstr ""
......
...@@ -5,17 +5,18 @@ ...@@ -5,17 +5,18 @@
interface LocoArrayInterface extends ArrayAccess, Iterator, Countable, JsonSerializable { public function getArrayCopy(); } interface LocoArrayInterface extends ArrayAccess, Iterator, Countable, JsonSerializable { public function getArrayCopy(); }
class LocoHeaders extends ArrayIterator implements LocoArrayInterface { private $map = array(); public function __construct(array $raw = array() ){ if( $raw ){ $keys = array_keys( $raw ); $this->map = array_combine( array_map( 'strtolower', $keys ), $keys ); parent::__construct($raw); } } public function normalize( $key ){ $k = strtolower($key); return isset($this->map[$k]) ? $this->map[$k] : null; } public function add($key, $val ){ $this->offsetSet( $key, $val ); return $this; } public function __toString(){ $pairs = array(); foreach( $this as $key => $val ){ $pairs[] = $key.': '.$val; } return implode("\n", $pairs ); } public function trimmed($prop ){ return trim( $this->__get($prop) ); } public function has($key ){ $k = strtolower($key); return isset($this->map[$k]); } public function __get($key ){ return $this->offsetGet( $key ); } public function __set($key, $val ){ $this->offsetSet( $key, $val ); } public function offsetExists($k ){ return ! is_null( $this->normalize($k) ); } public function offsetGet($k ){ $k = $this->normalize($k); if( is_null($k) ){ return ''; } return parent::offsetGet($k); } public function offsetSet($key, $v ){ $k = strtolower($key); if( isset($this->map[$k]) && $key !== $this->map[$k] ){ parent::offsetUnset( $this->map[$k] ); } $this->map[$k] = $key; parent::offsetSet( $key, $v ); } public function offsetUnset($key ){ $k = strtolower($key); if( isset($this->map[$k]) ){ parent::offsetUnset( $this->map[$k] ); unset( $this->map[$k] ); } } public function jsonSerialize(){ return $this->getArrayCopy(); } public function keys(){ trigger_error('Is this required?', E_USER_NOTICE); return array_values( $this->map ); } } class LocoHeaders extends ArrayIterator implements LocoArrayInterface { private $map = array(); public function __construct(array $raw = array() ){ if( $raw ){ $keys = array_keys( $raw ); $this->map = array_combine( array_map( 'strtolower', $keys ), $keys ); parent::__construct($raw); } } public function normalize( $key ){ $k = strtolower($key); return isset($this->map[$k]) ? $this->map[$k] : null; } public function add($key, $val ){ $this->offsetSet( $key, $val ); return $this; } public function __toString(){ $pairs = array(); foreach( $this as $key => $val ){ $pairs[] = $key.': '.$val; } return implode("\n", $pairs ); } public function trimmed($prop ){ return trim( $this->__get($prop) ); } public function has($key ){ $k = strtolower($key); return isset($this->map[$k]); } public function __get($key ){ return $this->offsetGet( $key ); } public function __set($key, $val ){ $this->offsetSet( $key, $val ); } public function offsetExists($k ){ return ! is_null( $this->normalize($k) ); } public function offsetGet($k ){ $k = $this->normalize($k); if( is_null($k) ){ return ''; } return parent::offsetGet($k); } public function offsetSet($key, $v ){ $k = strtolower($key); if( isset($this->map[$k]) && $key !== $this->map[$k] ){ parent::offsetUnset( $this->map[$k] ); } $this->map[$k] = $key; parent::offsetSet( $key, $v ); } public function offsetUnset($key ){ $k = strtolower($key); if( isset($this->map[$k]) ){ parent::offsetUnset( $this->map[$k] ); unset( $this->map[$k] ); } } public function jsonSerialize(){ return $this->getArrayCopy(); } public function keys(){ trigger_error('Is this required?', E_USER_NOTICE); return array_values( $this->map ); } }
function loco_normalize_charset( $cs ){ if( preg_match('/^UTF-?8$/i',$cs) ){ return 'UTF-8'; } $aliases = @mb_encoding_aliases($cs); if( false === $aliases ){ throw new InvalidArgumentException('Unsupported character encoding: '.$cs ); } if( $r = preg_grep('/^ISO[-_]\\d+[-_]\\d+$/i',$aliases) ){ $cs = current($aliases); $cs = strtr( strtoupper($cs), '_', '-' ); } else if( in_array('US-ASCII',$aliases,true) ){ $cs = 'US-ASCII'; } return $cs; } function loco_normalize_charset( $cs ){ if( preg_match('/^UTF-?8$/i',$cs) ){ return 'UTF-8'; } $aliases = @mb_encoding_aliases($cs); if( false === $aliases ){ throw new InvalidArgumentException('Unsupported character encoding: '.$cs ); } if( $r = preg_grep('/^ISO[-_]\\d+[-_]\\d+$/i',$aliases) ){ $cs = current($aliases); $cs = strtr( strtoupper($cs), '_', '-' ); } else if( in_array('US-ASCII',$aliases,true) ){ $cs = 'US-ASCII'; } return $cs; }
class LocoPoHeaders extends LocoHeaders { private $cs; public function getCharset(){ $cs = $this->cs; if( is_null($cs) ){ $cs = ''; $raw = $this->offsetGet('content-type'); if( $raw && preg_match('!\\bcharset[= ]+([-\\w]+)!',$raw,$r) ){ try { $cs = loco_normalize_charset($r[1]); } catch( InvalidArgumentException $e ){ $cs = null; } catch( Throwable $e ){ trigger_error( $e->getMessage(), E_USER_NOTICE ); $cs = null; } } $this->cs = $cs; } return $cs; } public function setCharset( $to ){ $to = loco_normalize_charset($to); $from = $this->getCharset(); $this->cs = $to; $this['Content-Type'] = 'text/plain; charset='.$to; if( $from && $from !== $to ){ foreach( $this as $key => $val ){ $this[$key] = mb_convert_encoding($val,$to,$from); } } return $to; } public static function fromMsgstr( $str ){ $headers = new LocoPoHeaders; $key = ''; foreach( preg_split('/[\\r\\n]+/',$str) as $line ){ $i = strpos($line,':'); if( is_int($i) ){ $key = trim( substr($line,0,$i), " \t" ); $headers->offsetSet( $key, ltrim( substr($line,++$i)," \t" ) ); } else if( '' !== $key ){ $headers->offsetSet( $key, $headers->offsetGet($key)."\n".$line ); } } $cs = $headers->getCharset(); if( $cs && 'UTF-8' !== $cs && 'UTF-8' !== mb_detect_encoding($str,array('UTF-8',$cs),true) ){ foreach( $headers as $key => $val ){ $headers[$key] = mb_convert_encoding($val,'UTF-8',array($cs)); } } return $headers; } public static function fromSource( $raw ){ $po = new LocoPoParser($raw); $po->parse(0); return $po->getHeader(); } } class LocoPoHeaders extends LocoHeaders { private $cs = null; public function getCharset(){ $cs = $this->cs; if( is_null($cs) ){ $cs = ''; $raw = $this->offsetGet('content-type'); if( $raw && preg_match('!\\bcharset[= ]+([-\\w]+)!',$raw,$r) ){ try { $cs = loco_normalize_charset($r[1]); } catch( InvalidArgumentException $e ){ $cs = null; } catch( Throwable $e ){ trigger_error( $e->getMessage(), E_USER_NOTICE ); $cs = null; } } $this->cs = $cs; } return $cs; } public function setCharset( $to ){ $to = loco_normalize_charset($to); $from = $this->getCharset(); $this->cs = $to; $this['Content-Type'] = 'text/plain; charset='.$to; if( $from && $from !== $to ){ foreach( $this as $key => $val ){ $this[$key] = mb_convert_encoding($val,$to,$from); } } return $to; } public static function fromMsgstr( $str ){ $headers = new LocoPoHeaders; $key = ''; foreach( preg_split('/[\\r\\n]+/',$str) as $line ){ $i = strpos($line,':'); if( is_int($i) ){ $key = trim( substr($line,0,$i), " \t" ); $headers->offsetSet( $key, ltrim( substr($line,++$i)," \t" ) ); } else if( '' !== $key ){ $headers->offsetSet( $key, $headers->offsetGet($key)."\n".$line ); } } $cs = $headers->getCharset(); if( $cs && 'UTF-8' !== $cs && 'UTF-8' !== mb_detect_encoding($str,array('UTF-8',$cs),true) ){ foreach( $headers as $key => $val ){ $headers[$key] = mb_convert_encoding($val,'UTF-8',array($cs)); } } return $headers; } public static function fromSource( $raw ){ $po = new LocoPoParser($raw); $po->parse(0); return $po->getHeader(); } }
function loco_convert_utf8( $str, $enc ){ if( '' === $enc ){ if( false === preg_match('//u',$str) ){ $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } } else if( 'UTF-8' === $enc || 'US-ASCII' === $enc ){ if( false === preg_match('//u',$str) ){ throw new Loco_error_ParseException('Bad '.$enc.' encoding'); } } else if( 'ISO-8859-1' === $enc ) { $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } else { $str = mb_convert_encoding( $str, 'UTF-8', $enc ); } return $str; } function loco_convert_utf8( $str, $enc, $strict ){ if( '' === $enc || 'UTF-8' === $enc || 'US-ASCII' === $enc ){ if( false === preg_match('//u',$str) ){ if( $strict ){ $e = new Loco_error_ParseException( $enc ? 'Invalid '.$enc.' encoding' : 'Unknown character encoding' ); if( preg_match('/^(?:[\\x00-\\x7F]|[\\xC0-\\xDF][\\x80-\\xBF]|[\\xE0-\\xEF][\\x80-\\xBF]{2}|[\\xF0-\\xFF][\\x80-\\xBF]{3})*/',$str,$r) && $str !== $r[0] ){ $e->setOffsetContext( strlen($r[0]), $str ); } throw $e; } $str = loco_fix_utf8($str); } } else if( 'ISO-8859-1' === $enc ) { $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } else { $str = mb_convert_encoding( $str, 'UTF-8', $enc ); } return $str; }
abstract class LocoGettextParser { private $head; private $cs; abstract public function parse( $limit = -1 ); protected function setHeader( LocoPoHeaders $head ){ $this->head = $head; if( $cs = $head->getCharset() ){ if( is_null($this->cs) ){ $this->setCharset($cs); } } return $head; } public function getHeader(){ return $this->head; } protected function setCharset( $cs ){ $this->cs = $cs; } protected function getCharset(){ return $this->cs; } protected function str( $str ){ if( '' !== $str ){ $enc = (string) $this->cs; $str = loco_convert_utf8( $str, $enc ); } return $str; } } function loco_fix_utf8( $str ){ $fix = ''; while( is_string($str) && '' !== $str ){ if( preg_match('/^(?:[\\x00-\\x7F]|[\\xC0-\\xDF][\\x80-\\xBF]|[\\xE0-\\xEF][\\x80-\\xBF]{2}|[\\xF0-\\xFF][\\x80-\\xBF]{3})+/',$str,$r) ){ $fix .= $r[0]; $str = substr($str, strlen($r[0]) ); } else { $fix.= mb_convert_encoding( $str[0], 'UTF-8', 'cp1252' ); $str = substr($str,1); } } return loco_convert_utf8($fix,'',true); }
abstract class LocoGettextParser { private $head = null; private $cs = ''; abstract public function parse( $limit = -1 ); protected function setHeader( LocoPoHeaders $head ){ $this->head = $head; $cs = $head->getCharset(); if( is_string($cs) && '' !== $cs ){ if( '' === $this->cs ){ $this->setCharset($cs); } } return $head; } public function getHeader(){ return $this->head; } protected function setCharset( $cs ){ $this->cs = $cs; } protected function getCharset(){ return $this->cs; } protected function str( $str ){ if( '' !== $str ){ $str = loco_convert_utf8($str,$this->cs,false); } return $str; } }
function loco_remove_bom( $s, &$c ){ $bom = substr($s,0,2); if( "\xFF\xFE" === $bom ){ $c = 'UTF-16LE'; return substr($s,2); } if( "\xFE\xFF" === $bom ){ $c = 'UTF-16BE'; return substr($s,2); } if( "\xEF\xBB" === $bom && "\xBF" === $s[2] ){ $c = 'UTF-8'; return substr($s,3); } $c = ''; return $s; } function loco_remove_bom( $s, &$c ){ $bom = substr($s,0,2); if( "\xFF\xFE" === $bom ){ $c = 'UTF-16LE'; return substr($s,2); } if( "\xFE\xFF" === $bom ){ $c = 'UTF-16BE'; return substr($s,2); } if( "\xEF\xBB" === $bom && "\xBF" === $s[2] ){ $c = 'UTF-8'; return substr($s,3); } $c = ''; return $s; }
function loco_parse_reference_id( $refs, &$_id ){ if( false === ( $n = strpos($refs,'loco:') ) ){ $_id = ''; return $refs; } $_id = substr($refs, $n+5, 24 ); $refs = substr_replace( $refs, '', $n, 29 ); return trim( $refs ); } function loco_parse_reference_id( $refs, &$_id ){ if( false === ( $n = strpos($refs,'loco:') ) ){ $_id = ''; return $refs; } $_id = substr($refs, $n+5, 24 ); $refs = substr_replace( $refs, '', $n, 29 ); return trim( $refs ); }
class LocoPoParser extends LocoGettextParser implements Iterator { private $lines = array(); private $i; private $k; private $m; public function __construct( $src ){ if( '' !== $src ){ $src = loco_remove_bom($src,$cs); if( $cs && 'UTF-8' !== $cs ){ $src = mb_convert_encoding( $src, 'UTF-8', array($cs) ); } if( 'UTF-8' === mb_detect_encoding($src,array('UTF-8','ISO-8859-1'),true) ){ $this->setCharset('UTF-8'); } $this->lines = preg_split('/(\\r\\n?|\\n)/', $src ); } } public function rewind(){ $this->i = -1; $this->k = -1; $this->next(); } public function valid(){ return is_int($this->i); } public function key(){ return $this->k; } public function current(){ return $this->m; } public function next(){ $valid = false; $entry = array( '#' => array(), 'id' => array(null), 'str' => array(null) ); $i = $this->i; while( array_key_exists(++$i,$this->lines) ){ $line = $this->lines[$i]; try { if( '' === $line ){ if( $valid ){ break; } continue; } $c = $line[0]; if( '#' === $c ){ if( $valid ){ $i--; break; } if( '#' === $line ){ continue; } $f = $line[1]; $entry['#'][$f][] = trim( substr( $line, 1+strlen($f) ), "/ \n\r\t" ); } else if( preg_match('/^msg(id(?:_plural)?|ctxt|str(?:\\[(\\d+)])?)[ \\t]*/', $line, $r ) ){ if( isset($r[2]) ){ $key = 'str'; $idx = (int) $r[2]; } else { $key = $r[1]; $idx = 0; } if( $valid && 'str' !== $key && null !== $entry['str'][0] ){ $i--; break; } $snip = strlen($r[0]); if( '"' !== substr($line,$snip,1) ){ throw new Exception('Expected " to follow msg'.$key); } $val = ''; $line = substr($line,$snip); while( true ){ if( '"' === $line || '"' !== substr($line,-1) ){ throw new Exception('Unterminated msg'.$key ); } $val .= substr( $line, 1, -1 ); $j = $i + 1; if( array_key_exists($j,$this->lines) && ( $line = $this->lines[$j] ) && '"' === $line[0] ){ $i = $j; } else { break; } } if( ! $valid ){ $valid = true; } if( 'id_plural' === $key ){ $key = 'id'; $idx = 1; } $entry[$key][$idx] = stripcslashes($val); } else if( preg_match('/^[ \\t]+$/',$line) ){ if( $valid ) { break; } } else if( '"' === $c ){ throw new Exception('String encountered without keyword'); } else { throw new Exception('Junk'); } } catch( Exception $e ){ } } if( $valid ){ ++$this->k; $this->i = $i; $this->m = $entry; } else { $this->i = null; $this->k = null; $this->m = null; } } public function parse( $limit = -1 ){ $this->rewind(); if( ! $this->valid() ){ throw new Loco_error_ParseException('Invalid PO file'); } $i = -1; $assets = array(); $entry = $this->current(); if( '' !== $entry['id'][0] || isset($entry['ctxt']) || is_null($entry['str'][0]) ){ $head = $this->setHeader( new LocoPoHeaders ); } else { $head = $this->setHeader( LocoPoHeaders::fromMsgstr($entry['str'][0]) ); } $lk = $head['X-Loco-Lookup']; while( $this->valid() ){ $entry = $this->current(); $this->next(); $msgid = $entry['id'][0]; if( is_null($msgid) ){ continue; } if( ++$i === $limit ){ return $assets; } $asset = array( 'source' => $this->str( $msgid ), 'target' => $this->str( (string) $entry['str'][0] ), 'context' => null, ); $prev_entry = null; if( isset($entry['ctxt']) ){ $asset['context'] = $this->str( $entry['ctxt'][0] ); } $cmt = $entry['#']; if( isset($cmt[' ']) ){ $asset['comment'] = $this->str( implode("\n", $cmt[' '] ) ); } if( isset($cmt['.']) ){ $asset['notes'] = $this->str( implode("\n", $cmt['.'] ) ); } if( isset($cmt[':']) ){ if( $refs = implode( ' ', $cmt[':'] ) ) { $refs = $this->str($refs); if( $refs = loco_parse_reference_id( $refs, $_id ) ){ $asset['refs'] = $refs; } if( $_id ){ $asset['_id'] = $_id; } } } if( isset($cmt[',']) ){ foreach( $cmt[','] as $flags ){ foreach( explode(',',$flags) as $flag ){ if( $flag = trim($flag," \t") ){ if( preg_match('/^((?:no-)?\w+)-format/', $flag, $r ) ){ $asset['format'] = $r[1]; } else if( 'fuzzy' === $flag ){ $asset['flag'] = 4; } } } } } if( isset($cmt['|']) ){ $p = new LocoPoParser(''); $p->lines = $cmt['|']; $p->setCharset( $this->getCharset() ); try { $prev_entry = $p->parse(); } catch( Loco_error_ParseException $e ){ } if( $prev_entry ){ $msgid = $prev_entry[0]['source']; if( $lk && 'text' !== $lk ){ $asset[$lk] = $asset['source']; $asset['source'] = $msgid; } else if( 'loco:' === substr($msgid,0,5) ){ $asset['_id'] = substr($msgid,5); } else { $asset['prev'] = $prev_entry; $prev_entry = null; } } } $assets[] = $asset; if( isset($entry['id'][1]) ){ $idx = 0; $pidx = count($assets) - 1; $num = max( 2, count($entry['str']) ); while( ++$idx < $num ){ $plural = array( 'source' => '', 'target' => isset($entry['str'][$idx]) ? $this->str($entry['str'][$idx]) : '', 'plural' => $idx, 'parent' => $pidx, ); if( 1 === $idx ){ $plural['source'] = $this->str($entry['id'][1]); if( is_array($prev_entry) && isset($prev_entry[1]) ){ if( $lk && 'text' !== $lk ){ $plural[$lk] = $plural['source']; $plural['source'] = $prev_entry[1]['source']; } } } if( isset($asset['flag']) ){ $plural['flag'] = $asset['flag']; } $assets[] = $plural; } } } if( -1 === $i ){ throw new Loco_error_ParseException('Invalid PO file'); } else if( 0 === $i && '' === $assets[0]['source'] && '' === $assets[0]['target'] ){ throw new Loco_error_ParseException('Invalid PO file' ); } return $assets; } } class LocoPoParser extends LocoGettextParser implements Iterator { private $lines = array(); private $i; private $k; private $m; public function __construct( $src ){ if( '' !== $src ){ $src = loco_remove_bom($src,$cs); if( $cs && 'UTF-8' !== $cs ){ $src = mb_convert_encoding( $src, 'UTF-8', $cs ); $cs = 'UTF-8'; } if( 'UTF-8' === $cs ){ $this->setCharset('UTF-8'); } $this->lines = preg_split('/(\\r\\n?|\\n)/', $src ); } } public function rewind(){ $this->i = -1; $this->k = -1; $this->next(); } public function valid(){ return is_int($this->i); } public function key(){ return $this->k; } public function current(){ return $this->m; } public function next(){ $valid = false; $entry = array( '#' => array(), 'id' => array(null), 'str' => array(null) ); $i = $this->i; while( array_key_exists(++$i,$this->lines) ){ $line = $this->lines[$i]; try { if( '' === $line ){ if( $valid ){ break; } continue; } $c = $line[0]; if( '#' === $c ){ if( $valid ){ $i--; break; } if( '#' === $line ){ continue; } $f = $line[1]; $entry['#'][$f][] = trim( substr( $line, 1+strlen($f) ), "/ \n\r\t" ); } else if( preg_match('/^msg(id(?:_plural)?|ctxt|str(?:\\[(\\d+)])?)[ \\t]*/', $line, $r ) ){ if( isset($r[2]) ){ $key = 'str'; $idx = (int) $r[2]; } else { $key = $r[1]; $idx = 0; } if( $valid && 'str' !== $key && null !== $entry['str'][0] ){ $i--; break; } $snip = strlen($r[0]); if( '"' !== substr($line,$snip,1) ){ throw new Exception('Expected " to follow msg'.$key); } $val = ''; $line = substr($line,$snip); while( true ){ if( '"' === $line || '"' !== substr($line,-1) ){ throw new Exception('Unterminated msg'.$key ); } $val .= substr( $line, 1, -1 ); $j = $i + 1; if( array_key_exists($j,$this->lines) && ( $line = $this->lines[$j] ) && '"' === $line[0] ){ $i = $j; } else { break; } } if( ! $valid ){ $valid = true; } if( 'id_plural' === $key ){ $key = 'id'; $idx = 1; } $entry[$key][$idx] = stripcslashes($val); } else if( preg_match('/^[ \\t]+$/',$line) ){ if( $valid ) { break; } } else if( '"' === $c ){ throw new Exception('String encountered without keyword'); } else { throw new Exception('Junk'); } } catch( Exception $e ){ } } if( $valid ){ ++$this->k; $this->i = $i; $this->m = $entry; } else { $this->i = null; $this->k = null; $this->m = null; } } public function parse( $limit = -1 ){ $this->rewind(); if( ! $this->valid() ){ throw new Loco_error_ParseException('Invalid PO file'); } $i = -1; $assets = array(); $entry = $this->current(); if( '' !== $entry['id'][0] || isset($entry['ctxt']) || is_null($entry['str'][0]) ){ $head = $this->setHeader( new LocoPoHeaders ); } else { $head = $this->setHeader( LocoPoHeaders::fromMsgstr($entry['str'][0]) ); } $lk = $head['X-Loco-Lookup']; while( $this->valid() ){ $entry = $this->current(); $this->next(); $msgid = $entry['id'][0]; if( is_null($msgid) ){ continue; } if( ++$i === $limit ){ return $assets; } $asset = array( 'source' => $this->str( $msgid ), 'target' => $this->str( (string) $entry['str'][0] ), 'context' => null, ); $prev_entry = null; if( isset($entry['ctxt']) ){ $asset['context'] = $this->str( $entry['ctxt'][0] ); } $cmt = $entry['#']; if( isset($cmt[' ']) ){ $asset['comment'] = $this->str( implode("\n", $cmt[' '] ) ); } if( isset($cmt['.']) ){ $asset['notes'] = $this->str( implode("\n", $cmt['.'] ) ); } if( isset($cmt[':']) ){ if( $refs = implode( ' ', $cmt[':'] ) ) { $refs = $this->str($refs); if( $refs = loco_parse_reference_id( $refs, $_id ) ){ $asset['refs'] = $refs; } if( $_id ){ $asset['_id'] = $_id; } } } if( isset($cmt[',']) ){ foreach( $cmt[','] as $flags ){ foreach( explode(',',$flags) as $flag ){ if( $flag = trim($flag," \t") ){ if( preg_match('/^((?:no-)?\w+)-format/', $flag, $r ) ){ $asset['format'] = $r[1]; } else if( 'fuzzy' === $flag ){ $asset['flag'] = 4; } } } } } if( isset($cmt['|']) ){ $p = new LocoPoParser(''); $p->lines = $cmt['|']; $p->setCharset( $this->getCharset() ); try { $prev_entry = $p->parse(); } catch( Loco_error_ParseException $e ){ } if( $prev_entry ){ $msgid = $prev_entry[0]['source']; if( $lk && 'text' !== $lk ){ $asset[$lk] = $asset['source']; $asset['source'] = $msgid; } else if( 'loco:' === substr($msgid,0,5) ){ $asset['_id'] = substr($msgid,5); } else { $asset['prev'] = $prev_entry; $prev_entry = null; } } } $assets[] = $asset; if( isset($entry['id'][1]) ){ $idx = 0; $pidx = count($assets) - 1; $num = max( 2, count($entry['str']) ); while( ++$idx < $num ){ $plural = array( 'source' => '', 'target' => isset($entry['str'][$idx]) ? $this->str($entry['str'][$idx]) : '', 'plural' => $idx, 'parent' => $pidx, ); if( 1 === $idx ){ $plural['source'] = $this->str($entry['id'][1]); if( is_array($prev_entry) && isset($prev_entry[1]) ){ if( $lk && 'text' !== $lk ){ $plural[$lk] = $plural['source']; $plural['source'] = $prev_entry[1]['source']; } } } if( isset($asset['flag']) ){ $plural['flag'] = $asset['flag']; } $assets[] = $plural; } } } if( -1 === $i ){ throw new Loco_error_ParseException('Invalid PO file'); } else if( 0 === $i && '' === $assets[0]['source'] && '' === $assets[0]['target'] ){ throw new Loco_error_ParseException('Invalid PO file' ); } return $assets; } }
class LocoMoParser extends LocoGettextParser { private $bin; private $be; private $n; private $o; private $t; private $v; public function __construct( $bin ){ $this->bin = $bin; } public function getAt( $idx ){ $offset = $this->targetOffset(); $offset += ( $idx * 8 ); $len = $this->integerAt( $offset ); $idx = $this->integerAt( $offset + 4 ); $txt = $this->bytes( $idx, $len ); if( false === strpos( $txt, "\0") ){ return $txt; } return explode( "\0", $txt ); } public function parse( $limit = -1 ){ $i = -1; $r = array(); $sourceOffset = $this->sourceOffset(); $targetOffset = $this->targetOffset(); $soffset = $sourceOffset; $toffset = $targetOffset; while( $soffset < $targetOffset ){ $len = $this->integerAt( $soffset ); $idx = $this->integerAt( $soffset + 4 ); $src = $this->bytes( $idx, $len ); $eot = strpos( $src, "\x04" ); if( false === $eot ){ $context = null; } else { $context = $this->str( substr($src, 0, $eot ) ); $src = substr( $src, $eot+1 ); } $sources = explode( "\0", $src, 2 ); $len = $this->integerAt( $toffset ); $idx = $this->integerAt( $toffset + 4 ); $targets = explode( "\0", $this->bytes( $idx, $len ) ); if( -1 === $i && '' === $sources[0] && is_null($context) ){ $this->setHeader( LocoPoHeaders::fromMsgstr($targets[0]) ); } if( ++$i === $limit ){ break; } $r[$i] = array( 'source' => $this->str( $sources[0] ), 'target' => $this->str( $targets[0] ), 'context' => $context, ); if( isset($sources[1]) ){ $p = count($r) - 1; $nforms = max( 2, count($targets) ); for( $i = 1; $i < $nforms; $i++ ){ $r[] = array( 'source' => isset($sources[$i]) ? $this->str( $sources[$i] ) : sprintf('%s (plural %u)',$r[$p]['source'],$i), 'target' => isset($targets[$i]) ? $this->str( $targets[$i] ) : '', 'parent' => $p, 'plural' => $i, ); } } $soffset += 8; $toffset += 8; } return $r; } public function isBigendian(){ if( is_null($this->be) ){ $str = $this->words( 0, 1 ); if( "\xDE\x12\x04\x95" === $str ){ $this->be = false; } else if( "\x95\x04\x12\xDE" === $str ){ $this->be = true; } else { throw new Loco_error_ParseException('Invalid MO format'); } } return $this->be; } public function version(){ if( is_null($this->v) ){ $this->v = $this->integerWord(1); } return $this->v; } public function count(){ if( is_null($this->n) ){ $this->n = $this->integerWord(2); } return $this->n; } public function sourceOffset(){ if( is_null($this->o) ){ $this->o = $this->integerWord(3); } return $this->o; } public function targetOffset(){ if( is_null($this->t) ){ $this->t = $this->integerWord(4); } return $this->t; } public function getHashTable(){ $s = $this->integerWord(5); $h = $this->integerWord(6); return $this->bytes( $h, $s * 4 ); } private function bytes( $offset, $length ){ $s = substr( $this->bin, $offset, $length ); if( strlen($s) !== $length ){ throw new Loco_error_ParseException('Failed to read '.$length.' bytes at ['.$offset.']' ); } return $s; } private function words( $offset, $length ){ return $this->bytes( $offset * 4, $length * 4 ); } private function integerWord( $offset ){ return $this->integerAt( $offset * 4 ); } private function integerAt( $offset ){ $str = $this->bytes( $offset, 4 ); $fmt = $this->isBigendian() ? 'N' : 'V'; $arr = unpack( $fmt, $str ); if( ! isset($arr[1]) || ! is_int($arr[1]) ){ throw new Loco_error_ParseException('Failed to read integer at byte '.$offset); } return $arr[1]; } } class LocoMoParser extends LocoGettextParser { private $bin; private $be; private $n; private $o; private $t; private $v; public function __construct( $bin ){ $this->bin = $bin; } public function getAt( $idx ){ $offset = $this->targetOffset(); $offset += ( $idx * 8 ); $len = $this->integerAt( $offset ); $idx = $this->integerAt( $offset + 4 ); $txt = $this->bytes( $idx, $len ); if( false === strpos( $txt, "\0") ){ return $txt; } return explode( "\0", $txt ); } public function parse( $limit = -1 ){ $i = -1; $r = array(); $sourceOffset = $this->sourceOffset(); $targetOffset = $this->targetOffset(); $soffset = $sourceOffset; $toffset = $targetOffset; while( $soffset < $targetOffset ){ $len = $this->integerAt( $soffset ); $idx = $this->integerAt( $soffset + 4 ); $src = $this->bytes( $idx, $len ); $eot = strpos( $src, "\x04" ); if( false === $eot ){ $context = null; } else { $context = $this->str( substr($src, 0, $eot ) ); $src = substr( $src, $eot+1 ); } $sources = explode( "\0", $src, 2 ); $len = $this->integerAt( $toffset ); $idx = $this->integerAt( $toffset + 4 ); $targets = explode( "\0", $this->bytes( $idx, $len ) ); if( -1 === $i && '' === $sources[0] && is_null($context) ){ $this->setHeader( LocoPoHeaders::fromMsgstr($targets[0]) ); } if( ++$i === $limit ){ break; } $r[$i] = array( 'source' => $this->str( $sources[0] ), 'target' => $this->str( $targets[0] ), 'context' => $context, ); if( isset($sources[1]) ){ $p = count($r) - 1; $nforms = max( 2, count($targets) ); for( $i = 1; $i < $nforms; $i++ ){ $r[] = array( 'source' => isset($sources[$i]) ? $this->str( $sources[$i] ) : sprintf('%s (plural %u)',$r[$p]['source'],$i), 'target' => isset($targets[$i]) ? $this->str( $targets[$i] ) : '', 'parent' => $p, 'plural' => $i, ); } } $soffset += 8; $toffset += 8; } return $r; } public function isBigendian(){ if( is_null($this->be) ){ $str = $this->words( 0, 1 ); if( "\xDE\x12\x04\x95" === $str ){ $this->be = false; } else if( "\x95\x04\x12\xDE" === $str ){ $this->be = true; } else { throw new Loco_error_ParseException('Invalid MO format'); } } return $this->be; } public function version(){ if( is_null($this->v) ){ $this->v = $this->integerWord(1); } return $this->v; } public function count(){ if( is_null($this->n) ){ $this->n = $this->integerWord(2); } return $this->n; } public function sourceOffset(){ if( is_null($this->o) ){ $this->o = $this->integerWord(3); } return $this->o; } public function targetOffset(){ if( is_null($this->t) ){ $this->t = $this->integerWord(4); } return $this->t; } public function getHashTable(){ $s = $this->integerWord(5); $h = $this->integerWord(6); return $this->bytes( $h, $s * 4 ); } private function bytes( $offset, $length ){ $s = substr( $this->bin, $offset, $length ); if( strlen($s) !== $length ){ throw new Loco_error_ParseException('Failed to read '.$length.' bytes at ['.$offset.']' ); } return $s; } private function words( $offset, $length ){ return $this->bytes( $offset * 4, $length * 4 ); } private function integerWord( $offset ){ return $this->integerAt( $offset * 4 ); } private function integerAt( $offset ){ $str = $this->bytes( $offset, 4 ); $fmt = $this->isBigendian() ? 'N' : 'V'; $arr = unpack( $fmt, $str ); if( ! isset($arr[1]) || ! is_int($arr[1]) ){ throw new Loco_error_ParseException('Failed to read integer at byte '.$offset); } return $arr[1]; } }
abstract class LocoPo { public static function pair( $key, $text, $width = 79, $eol = "\n", $esc = '\\n' ){ if( '' === $text ){ return $key.' ""'; } $text = addcslashes( $text, "\t\x0B\x0C\x07\x08\\\"" ); if( $esc ) { $text = preg_replace('/(?:\\r\\n?|\\n)/', $esc.$eol, $text, -1, $nbr ); } else { $eol = "\n"; $text = preg_replace_callback('/(?:\\r\\n?|\\n)/',array(__CLASS__,'replace_br'), $text, -1, $nbr ); } if( $nbr ){ } else if( $width && $width < mb_strlen($text,'UTF-8') + strlen($key) + 3 ){ } else { return $key.' "'.$text.'"'; } $lines = array( $key.' "' ); if( $width ){ $width -= 2; $a = '/^.{0,'.($width-1).'}[-– \\.,:;\\?!\\)\\]\\}\\>]/u'; $b = '/^[^-– \\.,:;\\?!\\)\\]\\}\\>]+/u'; foreach( explode($eol,$text) as $unwrapped ){ $length = mb_strlen( $unwrapped, 'UTF-8' ); while( $length > $width ){ if( preg_match( $a, $unwrapped, $r ) ){ $line = $r[0]; } else if( preg_match( $b, $unwrapped, $r ) ){ $line = $r[0]; } else { throw new Exception('Wrapping error'); } $lines[] = $line; $trunc = mb_strlen($line,'UTF-8'); $length -= $trunc; $unwrapped = (string) substr( $unwrapped, strlen($line) ); if( ( '' === $unwrapped && 0 !== $length ) || ( 0 === $length && '' !== $unwrapped ) ){ throw new Exception('Truncation error'); } } if( 0 !== $length ){ $lines[] = $unwrapped; } } } else { foreach( explode($eol,$text) as $unwrapped ){ $lines[] = $unwrapped; } } return implode('"'.$eol.'"',$lines).'"'; } private static function replace_br( array $r ){ return addcslashes($r[0],"\r\n")."\n"; } public static function refs( $text, $width = 76, $eol = "\n" ){ $text = preg_replace('/\\s+/u', ' ', $text ); if( $width ){ $text = wordwrap( $text, $width, $eol.'#: ', false ); } return '#: '.$text; } public static function prefix( $text, $prefix, $eol = "\n" ){ $lines = preg_split('/\\R/u', $text, -1 ); return $prefix.implode( $eol.$prefix, $lines ); } } abstract class LocoPo { public static function pair( $key, $text, $width = 79, $eol = "\n", $esc = '\\n' ){ if( '' === $text ){ return $key.' ""'; } $text = addcslashes( $text, "\t\x0B\x0C\x07\x08\\\"" ); if( $esc ) { $text = preg_replace('/(?:\\r\\n?|\\n)/', $esc.$eol, $text, -1, $nbr ); } else { $eol = "\n"; $text = preg_replace_callback('/(?:\\r\\n?|\\n)/',array(__CLASS__,'replace_br'), $text, -1, $nbr ); } if( $nbr ){ } else if( $width && $width < mb_strlen($text,'UTF-8') + strlen($key) + 3 ){ } else { return $key.' "'.$text.'"'; } $lines = array( $key.' "' ); if( $width ){ $width -= 2; $a = '/^.{0,'.($width-1).'}[-– \\.,:;\\?!\\)\\]\\}\\>]/u'; $b = '/^[^-– \\.,:;\\?!\\)\\]\\}\\>]+/u'; foreach( explode($eol,$text) as $unwrapped ){ $length = mb_strlen( $unwrapped, 'UTF-8' ); while( $length > $width ){ if( preg_match( $a, $unwrapped, $r ) ){ $line = $r[0]; } else if( preg_match( $b, $unwrapped, $r ) ){ $line = $r[0]; } else { throw new Exception('Wrapping error'); } $lines[] = $line; $trunc = mb_strlen($line,'UTF-8'); $length -= $trunc; $unwrapped = (string) substr( $unwrapped, strlen($line) ); if( ( '' === $unwrapped && 0 !== $length ) || ( 0 === $length && '' !== $unwrapped ) ){ throw new Exception('Truncation error'); } } if( 0 !== $length ){ $lines[] = $unwrapped; } } } else { foreach( explode($eol,$text) as $unwrapped ){ $lines[] = $unwrapped; } } return implode('"'.$eol.'"',$lines).'"'; } private static function replace_br( array $r ){ return addcslashes($r[0],"\r\n")."\n"; } public static function refs( $text, $width = 76, $eol = "\n" ){ $text = preg_replace('/\\s+/u', ' ', $text ); if( $width ){ $text = wordwrap( $text, $width, $eol.'#: ', false ); } return '#: '.$text; } public static function prefix( $text, $prefix, $eol = "\n" ){ return $prefix . implode($eol.$prefix, self::split($text) ); } public static function split( $text ){ $lines = preg_split('/\\R/u', $text ); if( false === $lines ){ if( false === preg_match('//u',$text) ){ $text = mb_convert_encoding( $text, 'UTF-8', 'cp1252' ); } $lines = preg_split('/\\r?\\n+/', $text ); } return $lines; } public static function trim( $text ){ $lines = array(); $deferred = null; foreach( explode("\n",$text) as $line ){ if( '' === $line ){ continue; } if( preg_match('/^msg[a-z]+(?:\\[\\d+])? ""/',$line) ){ $deferred = $line; continue; } if( $deferred && '"' === $line[0] ){ $lines[] = $deferred; $deferred = null; } $lines[] = $line; } return implode("\n",$lines); } }
class LocoPoIndex extends ArrayIterator { public function compare( LocoPoMessage $a, LocoPoMessage $b ){ $h = $a->getHash(); if( ! isset($this[$h]) ){ return 1; } $j = $b->getHash(); if( ! isset($this[$j]) ){ return -1; } return $this[$h] > $this[$j] ? 1 : -1; } } class LocoPoIndex extends ArrayIterator { public function compare( LocoPoMessage $a, LocoPoMessage $b ){ $h = $a->getHash(); if( ! isset($this[$h]) ){ return 1; } $j = $b->getHash(); if( ! isset($this[$j]) ){ return -1; } return $this[$h] > $this[$j] ? 1 : -1; } }
class LocoPoMessage extends ArrayObject { public function __construct( array $r ){ $r['key'] = $r['source']; parent::__construct($r); } public function __get( $prop ){ return isset($this[$prop]) ? $this[$prop] : null; } private function _getFlags(){ $flags = array(); $plurals = $this->__get('plurals'); if( 4 === $this->__get('flag') ){ $flags[] = 'fuzzy'; } else if( $plurals ){ foreach( $plurals as $child ){ if( 4 === $child->__get('flag') ){ $flags[] = 'fuzzy'; break; } } } if( $f = $this->__get('format') ){ $flags[] = $f.'-format'; } else if( isset($plurals[0]) && ( $f = $plurals[0]->format ) ){ $flags[] = $f.'-format'; } return $flags; } public function getHash(){ $hash = $this->getKey(); if( isset($this['plurals']) ){ foreach( $this['plurals'] as $p ){ $hash .= "\0".$p->getHash(); break; } } return $hash; } public function getKey(){ $msgid = (string) $this['source']; $msgctxt = (string) $this->__get('context'); if( '' !== $msgctxt ){ if( '' === $msgid ){ $msgid = '('.$msgctxt.')'; } $msgid = $msgctxt."\4".$msgid; } return $msgid; } public function __toString(){ return $this->render( 79, 76 ); } public function render( $width, $ref_width ){ $s = array(); try { if( $text = $this->__get('comment') ) { $s[] = LocoPo::prefix( $text, '# '); } if( $text = $this->__get('notes') ) { $s[] = LocoPo::prefix( $text, '#. '); } if( $text = $this->__get('refs') ){ $s[] = LocoPo::refs( $text, $ref_width ); } if( $texts = $this->_getFlags() ){ $s[] = '#, '.implode(', ',$texts); } $plurals = $this->__get('plurals'); $prev = $this->__get('prev'); if( is_array($prev) && $prev ){ foreach( new LocoPoIterator($prev) as $p ){ $text = $p->render( max(0,$width-3), 0 ); $text = preg_replace('/^msg[_a-z]+(\\[\\d+])? ""\\n/m','',$text); $s[] = LocoPo::prefix( rtrim($text,"\n"),'#| '); break; } } $text = $this->__get('context'); if( is_string($text) && '' !== $text ){ $s[] = LocoPo::pair('msgctxt', $text, $width ); } $s[] = LocoPo::pair( 'msgid', $this['key'], $width ); $target = $this['target']; if( is_array($plurals) ){ if( $plurals ){ foreach( $plurals as $i => $p ){ if( 0 === $i ){ $s[] = LocoPo::pair('msgid_plural', $p['key'], $width ); $s[] = LocoPo::pair('msgstr[0]', $target, $width ); } $s[] = LocoPo::pair('msgstr['.(++$i).']', $p['target'], $width ); } } else if( isset($this['plural_key']) ){ $s[] = LocoPo::pair('msgid_plural', $this['plural_key'], $width ); $s[] = LocoPo::pair('msgstr[0]', $target, $width ); } else { trigger_error('Missing plural_key in zero plural export'); $s[] = LocoPo::pair('msgstr', $target, $width ); } } else { $s[] = LocoPo::pair('msgstr', $target, $width ); } } catch( Exception $e ){ trigger_error( $e->getMessage(), E_USER_WARNING ); } return implode("\n",$s)."\n"; } } class LocoPoMessage extends ArrayObject { public function __construct( array $r ){ $r['key'] = $r['source']; parent::__construct($r); } public function __get( $prop ){ return $this->offsetExists($prop) ? $this->offsetGet($prop) : null; } private function _getFlags(){ $flags = array(); $plurals = $this->__get('plurals'); if( 4 === $this->__get('flag') ){ $flags[] = 'fuzzy'; } else if( $plurals ){ foreach( $plurals as $child ){ if( 4 === $child->__get('flag') ){ $flags[] = 'fuzzy'; break; } } } if( $f = $this->__get('format') ){ $flags[] = $f.'-format'; } else if( isset($plurals[0]) && ( $f = $plurals[0]->format ) ){ $flags[] = $f.'-format'; } return $flags; } public function getHash(){ $hash = $this->getKey(); if( $this->offsetExists('plurals') ){ foreach( $this['plurals'] as $p ){ $hash .= "\0".$p->getHash(); break; } } return $hash; } public function getKey(){ $msgid = (string) $this['source']; $msgctxt = (string) $this->__get('context'); if( '' !== $msgctxt ){ if( '' === $msgid ){ $msgid = '('.$msgctxt.')'; } $msgid = $msgctxt."\4".$msgid; } return $msgid; } public function __toString(){ return $this->render( 79, 76 ); } public function render( $width, $ref_width ){ $s = array(); try { if( $text = $this->__get('comment') ) { $s[] = LocoPo::prefix( $text, '# '); } if( $text = $this->__get('notes') ) { $s[] = LocoPo::prefix( $text, '#. '); } if( $text = $this->__get('refs') ){ $s[] = LocoPo::refs( $text, $ref_width ); } if( $texts = $this->_getFlags() ){ $s[] = '#, '.implode(', ',$texts); } $prev = $this->__get('prev'); if( is_array($prev) && $prev ){ foreach( new LocoPoIterator($prev) as $p ){ $text = $p->render( max(0,$width-3), 0 ); $s[] = LocoPo::prefix( LocoPo::trim($text),'#| '); break; } } $text = $this->__get('context'); if( is_string($text) && '' !== $text ){ $s[] = LocoPo::pair('msgctxt', $text, $width ); } $s[] = LocoPo::pair( 'msgid', $this['source'], $width ); $target = $this['target']; $plurals = $this->__get('plurals'); if( is_array($plurals) ){ if( $plurals ){ foreach( $plurals as $i => $p ){ if( 0 === $i ){ $s[] = LocoPo::pair('msgid_plural', $p['source'], $width ); $s[] = LocoPo::pair('msgstr[0]', $target, $width ); } $s[] = LocoPo::pair('msgstr['.(++$i).']', $p['target'], $width ); } } else if( isset($this['plural_key']) ){ $s[] = LocoPo::pair('msgid_plural', $this['plural_key'], $width ); $s[] = LocoPo::pair('msgstr[0]', $target, $width ); } else { trigger_error('Missing plural_key in zero plural export'); $s[] = LocoPo::pair('msgstr', $target, $width ); } } else { $s[] = LocoPo::pair('msgstr', $target, $width ); } } catch( Exception $e ){ trigger_error( $e->getMessage(), E_USER_WARNING ); } return implode("\n",$s)."\n"; } public function merge( LocoPoMessage $def, $translate = false ){ if( $def->getHash() !== $this->getHash() ){ $prev = array( 'source' => '', 'target' => '' ); $prev = $this->diff('source',$def,$prev); $prev = $this->diff('context',$def,$prev); $this['flag'] = 4; $this['prev'] = array( $prev ); $defPlural = $def->getPlural(0); $ourPlural = $this->getPlural(0); if( $defPlural && $ourPlural ) { $ourPlural->merge($defPlural); if( $ourPlural->offsetExists('prev') ) { $this['prev'][] = $ourPlural->prev[0]+array('parent'=>0,'plural'=>1); $ourPlural->offsetUnset('prev'); } } else if( $defPlural ){ $this['plurals'] = array( clone $defPlural ); } else if( $ourPlural ){ $this['prev'][] = $ourPlural->exportBasic() + array('parent'=>0,'plural'=>1); $this->offsetUnset('plurals'); } } foreach( array('notes','refs') as $f ){ if( $def->offsetExists($f) ){ $this->offsetSet($f,$def->offsetGet($f)); } else if( $this->offsetExists($f) ){ $this->offsetUnset($f); } } if( $translate && '' === $this['target'] && '' !== $def['target'] ){ $this['target'] = $def['target']; if( $def->offsetExists('comment') ) { $this['comment'] = $def['comment']; } if( $this->offsetExists('plurals') ){ foreach( $this['plurals'] as $i => $ourPlural ){ if( '' === $ourPlural['target'] ){ $defPlural = $def->getPlural($i); if( $defPlural ){ $ourPlural['target'] = $defPlural['target']; } } } } } } private function diff( $key, LocoPoMessage $def, array $prev ){ $old = $this->__get($key); $new = $def->__get($key); if( $new !== $old ){ $this->offsetSet($key,$new); if( is_string($old) && '' !== $old ){ $prev[$key] = $old; } } return $prev; } private function getPlural( $i ){ if( $this->offsetExists('plurals') ){ $plurals = $this->offsetGet('plurals'); if( is_array($plurals) && array_key_exists($i,$plurals) ){ return $plurals[$i]; } } return null; } private function exportBasic(){ return array( 'source' => $this['source'], 'context' => $this->context, 'target' => '', ); } public function export(){ $a = $this->getArrayCopy(); unset($a['key']); return $a; } public function countForms(){ $len = 1; if( $this->offsetExists('plurals') ){ $plurals = $this->offsetGet('plurals'); $len += count($plurals); } return $len; } public function strip(){ $this['target'] = ''; $plurals = $this->plurals; if( is_array($plurals) ){ foreach( $plurals as $p ){ $p->strip(); } } return $this; } }
class LocoPoIterator implements Iterator, Countable { private $po; private $headers; private $i; private $t; private $j; private $z; private $w = 79; public function __construct( $po ){ $this->po = $po; $this->t = count( $po ); if( ! isset($po[0]) ){ throw new InvalidArgumentException('Empty PO data'); } $h = $po[0]; if( '' === $h['source'] && empty($h['context']) ){ $this->z = 0; } else { $this->z = -1; } } public function count(){ return $this->t - ( $this->z + 1 ); } public function at( $index ){ return $this->po[ $this->z + $index ]; } public function wrap( $width ){ $width = (int) $width; if( $width > 0 ){ $this->w = max( 15, $width ); } else { $this->w = 0; } return $this; } public function rewind(){ $this->i = $this->z; $this->j = -1; $this->next(); } public function key(){ return $this->j; } public function valid(){ return is_int($this->i); } public function next(){ $i = $this->i; while( ++$i < $this->t ){ if( array_key_exists('parent',$this->po[$i]) ){ continue; } $this->j++; $this->i = $i; return; } $this->i = null; $this->j = null; } public function current(){ $i = $this->i; $po = $this->po; $parent = new LocoPoMessage( $po[$i] ); $plurals = array(); $nonseq = $parent->offsetExists('child'); $j = $nonseq ? $parent['child'] : $i+1; while( isset($po[$j]['parent']) && $i === $po[$j]['parent'] ){ $plurals[] = new LocoPoMessage($po[$j++]); } if( $plurals ){ $parent['plurals'] = $plurals; } return $parent; } public function getArrayCopy(){ $po = $this->po; if( 0 === $this->z ){ $po[0]['target'] = (string) $this->getHeaders(); } return $po; } public function getHeaders(){ if( ! $this->headers ){ $header = $this->po[0]; if( 0 === $this->z ){ $this->headers = LocoPoHeaders::fromMsgstr( $header['target'] ); } else { $this->headers = new LocoPoHeaders; } } return $this->headers; } public function initPo(){ if( 0 === $this->z ){ unset( $this->po[0]['flag'] ); } return $this; } public function initPot(){ if( 0 === $this->z ){ $this->po[0]['flag'] = 4; } return $this; } public function strip(){ $po = $this->po; $i = count($po); $z = $this->z; while( --$i > $z ){ $po[$i]['target'] = ''; } $this->po = $po; return $this; } public function __toString(){ try { return $this->render(); } catch( Exception $e ){ trigger_error( $e->getMessage(), E_USER_WARNING ); return ''; } } public function render( $sorter = null ){ $width = $this->w; $ref_width = max( 0, $width - 3 ); if( 0 === $this->z ){ $h = $this->po[0]; } else { $h = array( 'source' => '' ); } $h['target'] = (string) $this->getHeaders(); $msg = new LocoPoMessage( $h ); $s = $msg->render( $width, $ref_width ); if( $sorter ){ if( ! is_callable($sorter) ){ throw new InvalidArgumentException('Bad callback'); } $msgs = array(); foreach( $this as $msg ){ $msgs[] = $msg; } usort( $msgs, $sorter ); } else { $msgs = $this; } foreach( $msgs as $msg ){ $s .= "\n".$msg->render( $width, $ref_width ); } return $s; } public function exportRefs( $grep = '' ){ $a = array(); if( '' === $grep ) { $grep = '/(\\S+):\\d+/'; } else { $grep = '/(\\S*'.$grep.'):\\d+/'; } foreach( $this as $message ){ if( preg_match_all( $grep, (string) $message->refs, $r ) ){ foreach( $r[1] as $ref ) { $a[$ref][] = $message; } } } return $a; } public function splitRefs( array $map = null ){ $a = array(); foreach( $this as $message ){ $refs = ltrim( (string) $message->refs ); if( '' !== $refs ){ if( preg_match_all('/\\S+\\.([a-z]+):\\d+/', $refs, $r, PREG_SET_ORDER ) ){ $tmp = array(); foreach( $r as $rr ) { list( $ref, $ext ) = $rr; $tmp[$ext][$ref] = true; } foreach( $tmp as $ext => $refs ){ if( is_array($map) ){ if( isset($map[$ext]) ){ $ext = $map[$ext]; } else { continue; } } $message = clone $message; $message['refs'] = implode(' ',array_keys($refs) ); $a[$ext][] = $message; } } } } return $a; } public function getHashes(){ $a = array(); foreach( $this as $msg ){ $a[] = $msg->getHash(); } sort( $a, SORT_STRING ); return $a; } public function equalSource( LocoPoIterator $that ){ $a = $this->getHashes(); $b = $that->getHashes(); if( count($a) !== count($b) ){ return false; } foreach( $a as $i => $hash ){ if( $hash !== $b[$i] ){ return false; } } return true; } public function sort( $func = null ){ $order = array(); foreach( $this as $msg ){ $order[] = $msg; } if( is_null($func) ){ $func = array( __CLASS__, 'compare' ); } else if( ! is_callable($func) ){ throw new InvalidArgumentException('Bad callback'); } usort( $order, $func ); $po = array(); if( 0 === $this->z ){ $po[] = $this->po[0]; } foreach( $order as $msg ){ $po[] = $msg->getArrayCopy(); if( is_array( $plurals = $msg->plurals ) ){ $index = count($po) - 1; unset( $po[$index]['plurals'] ); foreach( $plurals as $p ){ $a = $p->getArrayCopy(); $a['parent'] = $index; $po[] = $a; } } } $this->po = $po; return $this; } public static function compare( LocoPoMessage $a, LocoPoMessage $b ){ $h = $a->getHash(); $j = $b->getHash(); $n = strcasecmp( $h, $j ); if( 0 === $n ){ $n = strcmp( $h, $j ); if( 0 === $n ){ return 0; } } return $n > 0 ? 1 : -1; } public function createSorter(){ $index = array(); foreach( $this as $i => $msg ){ $index[ $msg->getHash() ] = $i; } $obj = new LocoPoIndex( $index ); return array( $obj, 'compare' ); } } class LocoPoIterator implements Iterator, Countable { private $po; private $headers = null; private $i; private $t; private $j; private $z = 0; private $w = 79; public function __construct( $po ){ if( is_array($po) ){ $this->po = $po; } else if( $po instanceof Traversable ){ $this->po = iterator_to_array($po,false); } else { throw new InvalidArgumentException('PO data must be array or iterator'); } $this->t = count($po); if( 0 === $this->t ){ throw new InvalidArgumentException('Empty PO data'); } $h = $po[0]; if( '' !== $h['source'] || ( isset($h['context']) && '' !== $h['context'] ) || ( isset($po[1]['parent']) && 0 === $po[1]['parent'] ) ){ $this->z = -1; } } public function push( LocoPoMessage $p ){ $raw = $p->export(); $plurals = $p->plurals; unset($raw['plurals']); $i = count($this->po); $this->po[$i] = $raw; $this->t++; if( is_array($plurals) ) { $j = 0; foreach( $plurals as $p ) { $raw = $p->export(); $raw['parent'] = $i; $raw['plural'] = ++$j; $this->po[] = $raw; $this->t++; } } } public function __clone(){ if( $this->headers ){ $this->headers = new LocoPoHeaders( $this->headers->getArrayCopy() ); } } public function count(){ return $this->t - ( $this->z + 1 ); } public function wrap( $width ){ $width = (int) $width; if( $width > 0 ){ $this->w = max( 15, $width ); } else { $this->w = 0; } return $this; } public function rewind(){ $this->i = $this->z; $this->j = -1; $this->next(); } public function key(){ return $this->j; } public function valid(){ return is_int($this->i); } public function next(){ $i = $this->i; while( ++$i < $this->t ){ if( array_key_exists('parent',$this->po[$i]) ){ continue; } $this->j++; $this->i = $i; return; } $this->i = null; $this->j = null; } public function current(){ $i = $this->i; $po = $this->po; $parent = new LocoPoMessage( $po[$i] ); $plurals = array(); $nonseq = $parent->offsetExists('child'); $j = $nonseq ? $parent['child'] : $i+1; while( isset($po[$j]['parent']) && $i === $po[$j]['parent'] ){ $plurals[] = new LocoPoMessage($po[$j++]); } if( $plurals ){ $parent['plurals'] = $plurals; } return $parent; } public function getArrayCopy(){ $po = $this->po; if( 0 === $this->z ){ $po[0]['target'] = (string) $this->getHeaders(); } return $po; } public function clear(){ if( 0 === $this->z ){ $this->po = array( $this->po[0] ); $this->t = 1; } else { $this->po = array(); $this->t = 0; } } public function getHeaders(){ if( is_null($this->headers) ){ $header = $this->po[0]; if( 0 === $this->z ){ $this->headers = LocoPoHeaders::fromMsgstr( $header['target'] ); } else { $this->headers = new LocoPoHeaders; } } return $this->headers; } public function initPo(){ if( 0 === $this->z ){ unset( $this->po[0]['flag'] ); } return $this; } public function initPot(){ if( 0 === $this->z ){ $this->po[0]['flag'] = 4; } return $this; } public function strip(){ $po = $this->po; $i = count($po); $z = $this->z; while( --$i > $z ){ $po[$i]['target'] = ''; } $this->po = $po; return $this; } public function __toString(){ try { return $this->render(); } catch( Exception $e ){ trigger_error( $e->getMessage(), E_USER_WARNING ); return ''; } } public function render( $sorter = null ){ $width = $this->w; $ref_width = max( 0, $width - 3 ); if( 0 === $this->z ){ $h = $this->po[0]; } else { $h = array( 'source' => '' ); } $h['target'] = (string) $this->getHeaders(); $msg = new LocoPoMessage( $h ); $s = $msg->render( $width, $ref_width ); if( $sorter ){ if( ! is_callable($sorter) ){ throw new InvalidArgumentException('Bad callback'); } $msgs = array(); foreach( $this as $msg ){ $msgs[] = $msg; } usort( $msgs, $sorter ); } else { $msgs = $this; } foreach( $msgs as $msg ){ $s .= "\n".$msg->render( $width, $ref_width ); } return $s; } public function exportRefs( $grep = '' ){ $a = array(); if( '' === $grep ) { $grep = '/(\\S+):\\d+/'; } else { $grep = '/(\\S*'.$grep.'):\\d+/'; } foreach( $this as $message ){ if( preg_match_all( $grep, (string) $message->refs, $r ) ){ foreach( $r[1] as $ref ) { $a[$ref][] = $message; } } } return $a; } public function splitRefs( array $map = null ){ $a = array(); foreach( $this as $message ){ $refs = ltrim( (string) $message->refs ); if( '' !== $refs ){ if( preg_match_all('/\\S+\\.([a-z]+):\\d+/', $refs, $r, PREG_SET_ORDER ) ){ $tmp = array(); foreach( $r as $rr ) { list( $ref, $ext ) = $rr; $tmp[$ext][$ref] = true; } foreach( $tmp as $ext => $refs ){ if( is_array($map) ){ if( isset($map[$ext]) ){ $ext = $map[$ext]; } else { continue; } } $message = clone $message; $message['refs'] = implode(' ',array_keys($refs) ); $a[$ext][] = $message; } } } } return $a; } public function getHashes(){ $a = array(); foreach( $this as $msg ){ $a[] = $msg->getHash(); } sort( $a, SORT_STRING ); return $a; } public function equalSource( LocoPoIterator $that ){ $a = $this->getHashes(); $b = $that->getHashes(); if( count($a) !== count($b) ){ return false; } foreach( $a as $i => $hash ){ if( $hash !== $b[$i] ){ return false; } } return true; } public function equal( LocoPoIterator $that ){ if( $this->t !== $that->t ){ return false; } $i = $this->z; $fields = array( 'source', 'context', 'notes', 'refs', 'target', 'comment', 'flag', 'parent', 'plural' ); while( ++$i < $this->t ){ $a = $this->po[$i]; $b = $that->po[$i]; foreach( $fields as $f ){ $af = isset($a[$f]) ? $a[$f] : ''; $bf = isset($b[$f]) ? $b[$f] : ''; if( $af !== $bf ){ return false; } } } return true; } public function sort( $func = null ){ $order = array(); foreach( $this as $msg ){ $order[] = $msg; } if( is_null($func) ){ $func = array( __CLASS__, 'compare' ); } else if( ! is_callable($func) ){ throw new InvalidArgumentException('Bad callback'); } usort( $order, $func ); $this->clear(); foreach( $order as $p ){ $this->push($p); } return $this; } public static function compare( LocoPoMessage $a, LocoPoMessage $b ){ $h = $a->getHash(); $j = $b->getHash(); $n = strcasecmp( $h, $j ); if( 0 === $n ){ $n = strcmp( $h, $j ); if( 0 === $n ){ return 0; } } return $n > 0 ? 1 : -1; } public function createSorter(){ $index = array(); foreach( $this as $i => $msg ){ $index[ $msg->getHash() ] = $i; } $obj = new LocoPoIndex( $index ); return array( $obj, 'compare' ); } }
class LocoMoTable { private $size = 0; private $bin = ''; private $map; public function __construct( $data = null ){ if( is_array($data) ){ $this->compile( $data ); } else if( $data ){ $this->parse( $data ); } } public function count(){ if( ! isset($this->size) ){ if( $this->bin ){ $this->size = (int) ( strlen( $this->bin ) / 4 ); } else if( is_array($this->map) ){ $this->size = count($this->map); } else { return 0; } if( ! self::is_prime($this->size) || $this->size < 3 ){ throw new Exception('Size expected to be prime number above 2, got '.$this->size); } } return $this->size; } public function bytes(){ return $this->count() * 4; } public function __toString(){ return $this->bin; } public function export(){ if( ! is_array($this->map) ){ $this->parse( $this->bin ); } return $this->map; } private function reset( $length ){ $this->size = max( 3, self::next_prime ( $length * 4 / 3 ) ); $this->bin = null; $this->map = array(); return $this->size; } public function compile( array $msgids ){ $hash_tab_size = $this->reset( count($msgids) ); $packed = array_fill( 0, $hash_tab_size, "\0\0\0\0" ); $j = 0; foreach( $msgids as $msgid ){ $hash_val = self::hashpjw( $msgid ); $idx = $hash_val % $hash_tab_size; if( array_key_exists($idx, $this->map) ){ $incr = 1 + ( $hash_val % ( $hash_tab_size - 2 ) ); do { $idx += $incr; if( $hash_val === $idx ){ throw new Exception('Unable to find empty slot in hash table'); } $idx %= $hash_tab_size; } while( array_key_exists($idx, $this->map ) ); } $this->map[$idx] = $j; $packed[$idx] = pack('V', ++$j ); } return $this->bin = implode('',$packed); } public function lookup( $msgid, array $msgids ){ $hash_val = self::hashpjw( $msgid ); $idx = $hash_val % $this->size; $incr = 1 + ( $hash_val % ( $this->size - 2 ) ); while( true ){ if( ! array_key_exists($idx, $this->map) ){ break; } $j = $this->map[$idx]; if( isset($msgids[$j]) && $msgid === $msgids[$j] ){ return $j; } $idx += $incr; if( $idx === $hash_val ){ break; } $idx %= $this->size; } return -1; } public function parse( $bin ){ $this->bin = (string) $bin; $this->size = null; $hash_tab_size = $this->count(); $this->map = array(); $idx = -1; $byte = 0; while( ++$idx < $hash_tab_size ){ $word = substr( $this->bin, $byte, 4 ); if( "\0\0\0\0" !== $word ){ list(,$j) = unpack('V', $word ); $this->map[$idx] = $j - 1; } $byte += 4; } return $this->map; } public static function hashpjw( $str ){ $i = -1; $hval = 0; $len = strlen($str); while( ++$i < $len ){ $ord = ord( substr($str,$i,1) ); $hval = ( $hval << 4 ) + $ord; $g = $hval & 0xf0000000; if( $g !== 0 ){ $hval ^= $g >> 24; $hval ^= $g; } } return $hval; } private static function next_prime( $seed ){ $seed |= 1; while ( ! self::is_prime($seed) ){ $seed += 2; } return $seed; } private static function is_prime( $num ) { if ($num === 1 ){ return false; } if( $num === 2 ){ return true; } if( $num % 2 == 0 ) { return false; } for( $i = 3; $i <= ceil(sqrt($num)); $i = $i + 2) { if($num % $i == 0 ){ return false; } } return true; } } class LocoMoTable { private $size = 0; private $bin = ''; private $map; public function __construct( $data = null ){ if( is_array($data) ){ $this->compile( $data ); } else if( $data ){ $this->parse( $data ); } } public function count(){ if( ! isset($this->size) ){ if( $this->bin ){ $this->size = (int) ( strlen( $this->bin ) / 4 ); } else if( is_array($this->map) ){ $this->size = count($this->map); } else { return 0; } if( ! self::is_prime($this->size) || $this->size < 3 ){ throw new Exception('Size expected to be prime number above 2, got '.$this->size); } } return $this->size; } public function bytes(){ return $this->count() * 4; } public function __toString(){ return $this->bin; } public function export(){ if( ! is_array($this->map) ){ $this->parse( $this->bin ); } return $this->map; } private function reset( $length ){ $this->size = max( 3, self::next_prime ( $length * 4 / 3 ) ); $this->bin = null; $this->map = array(); return $this->size; } public function compile( array $msgids ){ $hash_tab_size = $this->reset( count($msgids) ); $packed = array_fill( 0, $hash_tab_size, "\0\0\0\0" ); $j = 0; foreach( $msgids as $msgid ){ $hash_val = self::hashpjw( $msgid ); $idx = $hash_val % $hash_tab_size; if( array_key_exists($idx, $this->map) ){ $incr = 1 + ( $hash_val % ( $hash_tab_size - 2 ) ); do { $idx += $incr; if( $hash_val === $idx ){ throw new Exception('Unable to find empty slot in hash table'); } $idx %= $hash_tab_size; } while( array_key_exists($idx, $this->map ) ); } $this->map[$idx] = $j; $packed[$idx] = pack('V', ++$j ); } return $this->bin = implode('',$packed); } public function lookup( $msgid, array $msgids ){ $hash_val = self::hashpjw( $msgid ); $idx = $hash_val % $this->size; $incr = 1 + ( $hash_val % ( $this->size - 2 ) ); while( true ){ if( ! array_key_exists($idx, $this->map) ){ break; } $j = $this->map[$idx]; if( isset($msgids[$j]) && $msgid === $msgids[$j] ){ return $j; } $idx += $incr; if( $idx === $hash_val ){ break; } $idx %= $this->size; } return -1; } public function parse( $bin ){ $this->bin = (string) $bin; $this->size = null; $hash_tab_size = $this->count(); $this->map = array(); $idx = -1; $byte = 0; while( ++$idx < $hash_tab_size ){ $word = substr( $this->bin, $byte, 4 ); if( "\0\0\0\0" !== $word ){ list(,$j) = unpack('V', $word ); $this->map[$idx] = $j - 1; } $byte += 4; } return $this->map; } public static function hashpjw( $str ){ $i = -1; $hval = 0; $len = strlen($str); while( ++$i < $len ){ $ord = ord( substr($str,$i,1) ); $hval = ( $hval << 4 ) + $ord; $g = $hval & 0xf0000000; if( $g !== 0 ){ $hval ^= $g >> 24; $hval ^= $g; } } return $hval; } private static function next_prime( $seed ){ $seed |= 1; while ( ! self::is_prime($seed) ){ $seed += 2; } return $seed; } private static function is_prime( $num ) { if ($num === 1 ){ return false; } if( $num === 2 ){ return true; } if( $num % 2 == 0 ) { return false; } for( $i = 3; $i <= ceil(sqrt($num)); $i = $i + 2) { if($num % $i == 0 ){ return false; } } return true; } }
class LocoMo { private $bin; private $msgs; private $head; private $hash; private $use_fuzzy = false; private $cs; public function __construct( Iterator $export, LocoPoHeaders $head = null ){ if( $head ){ $this->head = $head; } else { $this->head = new LocoPoHeaders; $this->setHeader('Project-Id-Version','Loco'); } $this->msgs = $export; $this->bin = ''; } public function setCharset( $cs ){ $cs = $this->head->setCharset($cs); $this->cs = 'UTF-8' === $cs ? null : $cs; } public function enableHash(){ return $this->hash = new LocoMoTable; } public function useFuzzy(){ $this->use_fuzzy = true; } public function setHeader( $key, $val ){ $this->head->add($key, $val); return $this; } private function str( $s ){ $s = (string) $s; if( $cs = $this->cs ){ $s = mb_convert_encoding($s,$cs,array('UTF-8')); } return $s; } public function compile(){ $table = array(''); $sources = array(''); $targets = array( (string) $this->head ); $fuzzy_flag = 4; $skip_fuzzy = ! $this->use_fuzzy; foreach( $this->msgs as $r ){ if( $skip_fuzzy && isset($r['flag']) && $fuzzy_flag === $r['flag'] ){ continue; } $msgid = $this->str( $r['key'] ); if( isset($r['context']) ){ $msgctxt = $this->str( $r['context'] ); if( '' !== $msgctxt ){ if( '' === $msgid ){ $msgid = '('.$msgctxt.')'; } $msgid = $msgctxt."\x04".$msgid; } } if( '' === $msgid ){ continue; } $msgstr = $this->str( $r['target'] ); if( '' === $msgstr ){ continue; } $table[] = $msgid; if( isset($r['plurals']) ){ foreach( $r['plurals'] as $i => $p ){ if( $i === 0 ){ $msgid .= "\0".$p['key']; } $msgstr .= "\0".$p['target']; } } $sources[] = $msgid; $targets[] = $msgstr; } asort( $sources, SORT_STRING ); $this->bin = "\xDE\x12\x04\x95\x00\x00\x00\x00"; $n = count($sources); $this->writeInteger( $n ); $offset = 28; $this->writeInteger( $offset ); $offset += $n * 8; $this->writeInteger( $offset ); if( $this->hash ){ sort( $table, SORT_STRING ); $this->hash->compile( $table ); $s = $this->hash->count(); } else { $s = 0; } $this->writeInteger( $s ); $offset += $n * 8; $this->writeInteger( $offset ); if( $s ){ $offset += $s * 4; } $source = ''; foreach( $sources as $i => $str ){ $source .= $str."\0"; $this->writeInteger( $strlen = strlen($str) ); $this->writeInteger( $offset ); $offset += $strlen + 1; } $target = ''; foreach( array_keys($sources) as $i ){ $str = $targets[$i]; $target .= $str."\0"; $this->writeInteger( $strlen = strlen($str) ); $this->writeInteger( $offset ); $offset += $strlen + 1; } if( $this->hash ){ $this->bin .= $this->hash->__toString(); } $this->bin .= $source; $this->bin .= $target; return $this->bin; } private function writeInteger( $num ){ $this->bin .= pack( 'V', $num ); return $this; } } class LocoMo { private $bin; private $msgs; private $head; private $hash; private $use_fuzzy = false; private $cs; public function __construct( Iterator $export, LocoPoHeaders $head = null ){ if( $head ){ $this->head = $head; } else { $this->head = new LocoPoHeaders; $this->setHeader('Project-Id-Version','Loco'); } $this->msgs = $export; $this->bin = ''; } public function setCharset( $cs ){ $cs = $this->head->setCharset($cs); $this->cs = 'UTF-8' === $cs ? null : $cs; } public function enableHash(){ return $this->hash = new LocoMoTable; } public function useFuzzy(){ $this->use_fuzzy = true; } public function setHeader( $key, $val ){ $this->head->add($key, $val); return $this; } private function str( $s ){ $s = (string) $s; if( $cs = $this->cs ){ $s = mb_convert_encoding($s,$cs,array('UTF-8')); } return $s; } public function compile(){ $table = array(''); $sources = array(''); $targets = array( (string) $this->head ); $fuzzy_flag = 4; $skip_fuzzy = ! $this->use_fuzzy; foreach( $this->msgs as $r ){ if( $skip_fuzzy && isset($r['flag']) && $fuzzy_flag === $r['flag'] ){ continue; } $msgid = $this->str( $r['key'] ); if( isset($r['context']) ){ $msgctxt = $this->str( $r['context'] ); if( '' !== $msgctxt ){ if( '' === $msgid ){ $msgid = '('.$msgctxt.')'; } $msgid = $msgctxt."\x04".$msgid; } } if( '' === $msgid ){ continue; } $msgstr = $this->str( $r['target'] ); if( '' === $msgstr ){ continue; } $table[] = $msgid; if( isset($r['plurals']) ){ foreach( $r['plurals'] as $i => $p ){ if( $i === 0 ){ $msgid .= "\0".$p['key']; } $msgstr .= "\0".$p['target']; } } $sources[] = $msgid; $targets[] = $msgstr; } asort( $sources, SORT_STRING ); $this->bin = "\xDE\x12\x04\x95\x00\x00\x00\x00"; $n = count($sources); $this->writeInteger( $n ); $offset = 28; $this->writeInteger( $offset ); $offset += $n * 8; $this->writeInteger( $offset ); if( $this->hash ){ sort( $table, SORT_STRING ); $this->hash->compile( $table ); $s = $this->hash->count(); } else { $s = 0; } $this->writeInteger( $s ); $offset += $n * 8; $this->writeInteger( $offset ); if( $s ){ $offset += $s * 4; } $source = ''; foreach( $sources as $i => $str ){ $source .= $str."\0"; $this->writeInteger( $strlen = strlen($str) ); $this->writeInteger( $offset ); $offset += $strlen + 1; } $target = ''; foreach( array_keys($sources) as $i ){ $str = $targets[$i]; $target .= $str."\0"; $this->writeInteger( $strlen = strlen($str) ); $this->writeInteger( $offset ); $offset += $strlen + 1; } if( $this->hash ){ $this->bin .= $this->hash->__toString(); } $this->bin .= $source; $this->bin .= $target; return $this->bin; } private function writeInteger( $num ){ $this->bin .= pack( 'V', $num ); return $this; } }
interface LocoTokensInterface extends Iterator { public function advance(); public function ignore( array $a ); } interface LocoTokensInterface extends Iterator { public function advance(); public function ignore( array $a ); }
...@@ -23,10 +24,10 @@ class LocoTokenizer implements LocoTokensInterface { const T_LITERAL = 0; const ...@@ -23,10 +24,10 @@ class LocoTokenizer implements LocoTokensInterface { const T_LITERAL = 0; const
function loco_utf8_chr( $u ){ if( $u < 0x80 ){ if( $u < 0 ){ throw new RangeException( sprintf('%d is out of Unicode range', $u ) ); } return chr($u); } if( $u < 0x800 ) { return chr( ($u>>6) & 0x1F | 0xC0 ).chr( $u & 0x3F | 0x80 ); } if( $u < 0x10000 ) { return chr( $u>>12 & 15 | 0xE0 ).chr( $u>>6 & 0x3F | 0x80 ).chr( $u & 0x3F | 0x80 ); } if( $u < 0x110000 ) { return chr( $u>>18 & 7 | 0xF0 ).chr( $u>>12 & 0x3F | 0x80 ).chr( $u>>6 & 0x3F | 0x80 ).chr( $u & 0x3F | 0x80 ); } throw new RangeException( sprintf('\\x%X is out of Unicode range', $u ) ); } function loco_utf8_chr( $u ){ if( $u < 0x80 ){ if( $u < 0 ){ throw new RangeException( sprintf('%d is out of Unicode range', $u ) ); } return chr($u); } if( $u < 0x800 ) { return chr( ($u>>6) & 0x1F | 0xC0 ).chr( $u & 0x3F | 0x80 ); } if( $u < 0x10000 ) { return chr( $u>>12 & 15 | 0xE0 ).chr( $u>>6 & 0x3F | 0x80 ).chr( $u & 0x3F | 0x80 ); } if( $u < 0x110000 ) { return chr( $u>>18 & 7 | 0xF0 ).chr( $u>>12 & 0x3F | 0x80 ).chr( $u>>6 & 0x3F | 0x80 ).chr( $u & 0x3F | 0x80 ); } throw new RangeException( sprintf('\\x%X is out of Unicode range', $u ) ); }
function loco_resolve_surrogates( $s ){ return preg_replace_callback('/\\xED([\\xA0-\\xAF])([\\x80-\\xBF])\\xED([\\xB0-\\xBF])([\\x80-\\xBF])/', '_loco_resolve_surrogates', $s ); } function loco_resolve_surrogates( $s ){ return preg_replace_callback('/\\xED([\\xA0-\\xAF])([\\x80-\\xBF])\\xED([\\xB0-\\xBF])([\\x80-\\xBF])/', '_loco_resolve_surrogates', $s ); }
function _loco_resolve_surrogates( array $r ){ return loco_utf8_chr ( ( ( ( ( 832 | ( ord($r[1]) & 0x3F ) ) << 6 ) | ( ord($r[2]) & 0x3F ) ) - 0xD800 ) * 0x400 + ( ( ( ( 832 | ( ord($r[3]) & 0x3F ) ) << 6 ) | ( ord($r[4]) & 0x3F ) ) - 0xDC00 ) + 0x10000 ); } function _loco_resolve_surrogates( array $r ){ return loco_utf8_chr ( ( ( ( ( 832 | ( ord($r[1]) & 0x3F ) ) << 6 ) | ( ord($r[2]) & 0x3F ) ) - 0xD800 ) * 0x400 + ( ( ( ( 832 | ( ord($r[3]) & 0x3F ) ) << 6 ) | ( ord($r[4]) & 0x3F ) ) - 0xDC00 ) + 0x10000 ); }
class LocoEscapeParser { private $map; private $grep; public function __construct( array $map = array() ){ $this->map = $map; $rules = array('\\\\'); if( $map ){ $rules[] = '['.implode(array_keys($map)).']'; } if( ! isset($map['U']) ) { $rules[] = 'U[0-9A-Fa-f]{5,8}'; } if( ! isset($map['u']) ) { $rules[] = 'u(?:\\{[0-9A-Fa-f]+\\}|[0-9A-Fa-f]{1,4})(?:\\\\u(?:\\{[0-9A-Fa-f]+\\}|[0-9A-Fa-f]{1,4}))*'; } $this->grep = '/\\\\('.implode('|',$rules).')/'; } public function unescape( $s ){ if( '' !== $s ) { return $this->stripSlashes( preg_replace_callback($this->grep, array($this, 'unescapeMatch'), $s) ); } return ''; } public function unescapeMatch( array $r ){ $s = $r[0]; $c = $s[1]; if( isset($this->map[$c]) ){ return $this->map[$c]; } if( 'u' === $c ){ $str = ''; $surrogates = false; foreach( explode('\\u',$s) as $i => $h ){ if( '' !== $h ){ $h = ltrim( trim($h,'{}'),'0'); $u = intval($h,16); $str.= loco_utf8_chr($u); if( ! $surrogates ){ $surrogates = $u >= 0xD800 && $u <= 0xDBFF; } } } if( $surrogates ){ $str = loco_resolve_surrogates($str); } return $str; } if( 'U' === $c ){ return loco_utf8_chr( intval(substr($s,2),16) ); } if( 'x' === $c ){ return chr( intval(substr($s,2),16) ); } if( ctype_digit($c) ){ return chr( intval(substr($s,1),8) ); } return $s; } protected function stripSlashes( $s ){ return stripcslashes($s); } } class LocoEscapeParser { private $map; private $grep; public function __construct( array $map = array() ){ $this->map = $map; $rules = array('\\\\'); if( $map ){ $rules[] = '['.implode(array_keys($map)).']'; } if( ! isset($map['U']) ) { $rules[] = 'U[0-9A-Fa-f]{5,8}'; } if( ! isset($map['u']) ) { $rules[] = 'u(?:\\{[0-9A-Fa-f]+\\}|[0-9A-Fa-f]{1,4})(?:\\\\u(?:\\{[0-9A-Fa-f]+\\}|[0-9A-Fa-f]{1,4}))*'; } $this->grep = '/\\\\('.implode('|',$rules).')/'; } public function unescape( $s ){ if( '' !== $s ) { return $this->stripSlashes( preg_replace_callback($this->grep, array($this, 'unescapeMatch'), $s) ); } return ''; } public function unescapeMatch( array $r ){ $s = $r[0]; $c = $s[1]; if( isset($this->map[$c]) ){ return $this->map[$c]; } if( 'u' === $c ){ $str = ''; $surrogates = false; foreach( explode('\\u',$s) as $i => $h ){ if( '' !== $h ){ $h = ltrim( trim($h,'{}'),'0'); $u = intval($h,16); $str.= loco_utf8_chr($u); if( ! $surrogates ){ $surrogates = $u >= 0xD800 && $u <= 0xDBFF; } } } if( $surrogates ){ $str = loco_resolve_surrogates($str); } return $str; } if( 'U' === $c ){ return loco_utf8_chr( intval(substr($s,2),16) ); } if( 'x' === $c ){ return chr( intval(substr($s,2),16) ); } if( ctype_digit($c) ){ return chr( intval(substr($s,1),8) ); } return $s; } protected function stripSlashes( $s ){ return stripcslashes($s); } }
class LocoJsTokens extends LocoTokenizer { const T_KWORD = 1; const T_REGEX = 2; private static $lex; protected static $words = array( 'true' => 1, 'false' => 1, 'null' => 1, 'break' => T_BREAK, 'else' => T_ELSE, 'new' => T_NEW, 'var' => 1, 'case' => T_CASE, 'finally' => T_FINALLY, 'return' => T_RETURN, 'void' => 1, 'catch' => T_CATCH, 'for' => T_FOR, 'switch' => T_SWITCH, 'while' => T_WHILE, 'continue' => T_CONTINUE, 'function' => T_FUNCTION, 'this' => T_STRING, 'with' => 1, 'default' => T_DEFAULT, 'if' => T_IF, 'throw' => T_THROW, 'delete' => 1, 'in' => 1, 'try' => T_TRY, 'do' => T_DO, 'instanceof' => 1, 'typeof' => 1, ); public static function decapse( $encapsed ){ $s = substr($encapsed,1,-1); $l = self::$lex; if( is_null($l) ){ $l = new LocoEscapeParser( array( 'U' => 'U', 'a' => 'a', ) ); self::$lex = $l; } return $l->unescape($s); } public function __construct( $src = '' ){ $this->define('/^(?:\\\\u[0-9A-F]{4,4}|[$_\\pL\\p{Nl}])(?:\\\\u[0-9A-F]{4}|[$_\\pL\\pN\\p{Mn}\\p{Mc}\\p{Pc}])*/ui', array($this,'matchWord') ); $this->define('/^\\s+/u', T_WHITESPACE ); $this->define('!^//.*!', T_COMMENT ); $this->define('!^/\\*.*\\*/!Us', array($this,'matchComment') ); $this->define('/^"(?:\\\\.|[^\\r\\n\\p{Zl}\\p{Zp}"\\\\])*"/u', T_CONSTANT_ENCAPSED_STRING ); $this->define('/^\'(?:\\\\.|[^\\r\\n\\p{Zl}\\p{Zp}\'\\\\])*\'/u', T_CONSTANT_ENCAPSED_STRING ); $this->define('/^[-+;,<>.=:|&^!?*%~(){}[\\]]/'); parent::__construct($src); } public function matchWord( $s ){ if( array_key_exists($s,self::$words) ){ return self::$words[$s]; } return T_STRING; } public function matchComment( $s ){ if( '/**' === substr($s,0,3) ){ return T_DOC_COMMENT; } return T_COMMENT; } } class LocoJsTokens extends LocoTokenizer { const T_KWORD = 1; const T_REGEX = 2; private static $lex; protected static $words = array( 'true' => 1, 'false' => 1, 'null' => 1, 'break' => T_BREAK, 'else' => T_ELSE, 'new' => T_NEW, 'var' => 1, 'case' => T_CASE, 'finally' => T_FINALLY, 'return' => T_RETURN, 'void' => 1, 'catch' => T_CATCH, 'for' => T_FOR, 'switch' => T_SWITCH, 'while' => T_WHILE, 'continue' => T_CONTINUE, 'function' => T_FUNCTION, 'this' => T_STRING, 'with' => 1, 'default' => T_DEFAULT, 'if' => T_IF, 'throw' => T_THROW, 'delete' => 1, 'in' => 1, 'try' => T_TRY, 'do' => T_DO, 'instanceof' => 1, 'typeof' => 1, ); public static function decapse( $encapsed ){ $s = substr($encapsed,1,-1); $l = self::$lex; if( is_null($l) ){ $l = new LocoEscapeParser( array( 'U' => 'U', 'a' => 'a', ) ); self::$lex = $l; } return $l->unescape($s); } public function __construct( $src = '' ){ $this->define('/^(?:\\\\u[0-9A-F]{4,4}|[$_\\pL\\p{Nl}])(?:\\\\u[0-9A-F]{4}|[$_\\pL\\pN\\p{Mn}\\p{Mc}\\p{Pc}])*/ui', array($this,'matchWord') ); $this->define('/^\\s+/u', T_WHITESPACE ); $this->define('!^//.*!', T_COMMENT ); $this->define('!^/\\*.*\\*/!Us', array($this,'matchComment') ); $this->define('/^"(?:\\\\.|[^\\r\\n\\p{Zl}\\p{Zp}"\\\\])*"/u', T_CONSTANT_ENCAPSED_STRING ); $this->define('/^\'(?:\\\\.|[^\\r\\n\\p{Zl}\\p{Zp}\'\\\\])*\'/u', T_CONSTANT_ENCAPSED_STRING ); $this->define('/^[-+;,<>.=:|&^!?*%~(){}[\\]]/'); parent::__construct($src); } public function matchWord( $s ){ if( array_key_exists($s,self::$words) ){ return self::$words[$s]; } return T_STRING; } public function matchComment( $s ){ if( '/**' === substr($s,0,3) ){ return T_DOC_COMMENT; } return T_COMMENT; } }
class LocoExtracted implements Countable { private $exp = array(); private $reg = array(); private $dom = array(); private $dflt = ''; public function extractSource( LocoExtractor $ext, $src, $fileref = '' ){ $ext->extract( $this, $ext->tokenize($src), $fileref ); return $this; } public function export(){ return $this->exp; } public function count(){ return count( $this->exp ); } public function getDomainCounts(){ return $this->dom; } public function setDomain( $default ){ $this->dflt = (string) $default; return $this; } public function getDomain(){ return $this->dflt; } public function pushMeta( $source, $notes = '', $domain = null ){ if( ! $domain || '*' === $domain ){ $domain = $this->dflt; } $entry = array( 'id' => '', 'source' => $source, 'target' => '', 'notes' => $notes, ); if( $domain ){ $entry['domain'] = $domain; $key = $source."\1".$domain; } else { $key = $source; } return $this->pushMsgid( $key, $entry, $domain ); } public function pushMsgid( $key, array $entry, $domain ){ if( isset($this->reg[$key]) ){ $index = $this->reg[$key]; $clash = $this->exp[$index]; if( $value = $this->mergeField( $clash, $entry, 'refs', ' ') ){ $this->exp[$index]['refs'] = $value; } if( $value = $this->mergeField( $clash, $entry, 'notes', "\n") ){ $this->exp[$index]['notes'] = $value; } } else { $index = count($this->exp); $this->reg[$key] = $index; $this->exp[$index] = $entry; if( isset($this->dom[$domain]) ){ $this->dom[$domain]++; } else { $this->dom[$domain] = 1; } } return $index; } public function pushMsgidPlural( $skey, array $entry ){ $sindex = $entry['parent']; $pkey = $skey."\2"; if( ! array_key_exists($pkey,$this->reg) ){ $pindex = count($this->exp); $this->reg[$pkey] = $pindex; $this->exp[$pindex] = $entry; if( isset($entry['format']) && ! isset( $this->exp[$sindex]['format']) ) { $this->exp[$sindex]['format'] = $entry['format']; } if( $pindex !== $sindex + $entry['plural']) { $this->exp[$sindex]['child'] = $pindex; } } } public function mergeField( array $old, array $new, $field, $glue ){ $prev = isset($old[$field]) ? $old[$field] : ''; if( isset($new[$field]) ){ $text = $new[$field]; if( '' !== $prev && $prev !== $text ){ if( 'notes' === $field && preg_match( '/^'.preg_quote( rtrim($text,'. '),'/').'[. ]*$/mu', $prev ) ) { $text = $prev; } else { $text = $prev.$glue.$text; } } return $text; } return $prev; } public function filter( $domain ){ $map = array(); $newOffset = 1; $matchAll = '*' === $domain; $raw = array( array( 'id' => '', 'source' => '', 'target' => '', 'domain' => $matchAll ? '' : $domain, ) ); foreach( $this->exp as $oldOffset => $r ){ if( isset($r['parent']) ){ if( isset($map[$r['parent']]) ){ $r['parent'] = $map[ $r['parent'] ]; $raw[ $newOffset++ ] = $r; } } else { if( $matchAll ){ $match = true; } else if( isset($r['domain']) ){ $match = $domain === $r['domain']; } else { $match = $domain === ''; } if( $match ){ $map[ $oldOffset ] = $newOffset; $raw[ $newOffset++ ] = $r; } } } return $raw; } } class LocoExtracted implements Countable { private $exp = array(); private $reg = array(); private $dom = array(); private $dflt = ''; public function extractSource( LocoExtractor $ext, $src, $fileref = '' ){ $ext->extract( $this, $ext->tokenize($src), $fileref ); return $this; } public function export(){ return $this->exp; } public function count(){ return count( $this->exp ); } public function getDomainCounts(){ return $this->dom; } public function setDomain( $default ){ $this->dflt = (string) $default; return $this; } public function getDomain(){ return $this->dflt; } public function pushMeta( $source, $notes, $domain = null ){ if( ! $domain || '*' === $domain ){ $domain = $this->dflt; } $entry = array( 'id' => '', 'source' => $source, 'target' => '', 'notes' => $notes, ); if( $domain ){ $entry['domain'] = $domain; $key = $source."\1".$domain; } else { $key = $source; } return $this->pushMsgid( $key, $entry, $domain ); } public function pushMsgid( $key, array $entry, $domain ){ if( isset($this->reg[$key]) ){ $index = $this->reg[$key]; $clash = $this->exp[$index]; if( $value = $this->mergeField( $clash, $entry, 'refs', ' ') ){ $this->exp[$index]['refs'] = $value; } if( $value = $this->mergeField( $clash, $entry, 'notes', "\n") ){ $this->exp[$index]['notes'] = $value; } } else { $index = count($this->exp); $this->reg[$key] = $index; $this->exp[$index] = $entry; if( isset($this->dom[$domain]) ){ $this->dom[$domain]++; } else { $this->dom[$domain] = 1; } } return $index; } public function pushMsgidPlural( $skey, array $entry ){ $sindex = $entry['parent']; $pkey = $skey."\2"; if( ! array_key_exists($pkey,$this->reg) ){ $pindex = count($this->exp); $this->reg[$pkey] = $pindex; $this->exp[$pindex] = $entry; if( isset($entry['format']) && ! isset( $this->exp[$sindex]['format']) ) { $this->exp[$sindex]['format'] = $entry['format']; } if( $pindex !== $sindex + $entry['plural']) { $this->exp[$sindex]['child'] = $pindex; } } } public function mergeField( array $old, array $new, $field, $glue ){ $prev = isset($old[$field]) ? $old[$field] : ''; if( isset($new[$field]) ){ $text = $new[$field]; if( '' !== $prev && $prev !== $text ){ if( 'notes' === $field && preg_match( '/^'.preg_quote( rtrim($text,'. '),'/').'[. ]*$/mu', $prev ) ) { $text = $prev; } else { $text = $prev.$glue.$text; } } return $text; } return $prev; } public function filter( $domain ){ $map = array(); $newOffset = 1; $matchAll = '*' === $domain; $raw = array( array( 'id' => '', 'source' => '', 'target' => '', 'domain' => $matchAll ? '' : $domain, ) ); foreach( $this->exp as $oldOffset => $r ){ if( isset($r['parent']) ){ if( isset($map[$r['parent']]) ){ $r['parent'] = $map[ $r['parent'] ]; $raw[ $newOffset++ ] = $r; } } else { if( $matchAll ){ $match = true; } else if( isset($r['domain']) ){ $match = $domain === $r['domain']; } else { $match = $domain === ''; } if( $match ){ $map[ $oldOffset ] = $newOffset; $raw[ $newOffset++ ] = $r; } } } return $raw; } }
abstract class LocoExtractor { private $rules; private $wp = array(); private $domain; abstract public function tokenize( $src ); abstract public function extract( LocoExtracted $strings, LocoTokensInterface $tokens, $fileref = '' ); abstract protected function fsniff( $str ); abstract protected function decapse( $raw ); abstract protected function comment( $comment ); public function __construct( array $rules ){ $this->rules = $rules; } public function setDomain( $default ){ $this->domain = $default; return $this; } public function headerize( array $tags, $domain = '' ){ if( isset($this->wp[$domain]) ){ $this->wp[$domain] += $tags; } else { $this->wp[$domain] = $tags; } return $this; } protected function getHeaders(){ return $this->wp; } final public function extractSource( $src, $fileref ){ $strings = new LocoExtracted; $this->extract( $strings, $this->tokenize($src), $fileref ); return $strings; } public function rule( $s ){ return isset($this->rules[$s]) ? $this->rules[$s] : ''; } protected function push( LocoExtracted $strings, $rule, array $args, $comment = '', $ref = '' ){ $s = strpos( $rule, 's'); $p = strpos( $rule, 'p'); $c = strpos( $rule, 'c'); $d = strpos( $rule, 'd'); if( false === $s || ! isset($args[$s]) ){ return null; } $key = $args[$s]; if( ! is_string($key) ){ return null; } $msgid = $key; $entry = array( 'id' => '', 'source' => $msgid, 'target' => '', ); if( is_int($c) && isset($args[$c]) ){ $entry['context'] = $context = $args[$c]; $key .= "\0". $context; } else if( '' === $msgid ){ return null; } else { $context = null; } if( $ref ){ $entry['refs'] = $ref; } if( is_int($d) && array_key_exists($d,$args) ){ $domain = $args[$d]; if( is_null($domain) ){ $domain = ''; } } else { $domain = $this->domain or $domain = $strings->getDomain(); } if( is_string($domain) && '' !== $domain ){ $entry['domain'] = $domain; $key .= "\1".$domain; } $parse_printf = true; if( $comment = $this->comment($comment) ){ if( preg_match('/^xgettext:\\s*([-a-z]+)-format\\s*/mi', $comment, $r, PREG_OFFSET_CAPTURE ) ){ $entry['format'] = $r[1][0]; $comment = trim( substr_replace( $comment,'', $r[0][1], strlen($r[0][0]) ) ); $parse_printf = ( 'no-' === substr($entry['format'],0,3) ) ? false : null; } if( preg_match('/^references?:( *.+:\\d+)*\\s*/mi', $comment, $r, PREG_OFFSET_CAPTURE ) ){ $entry['refs'] = trim($r[1][0],' '); $comment = trim( substr_replace( $comment, '', $r[0][1], strlen($r[0][0]) ) ); } $entry['notes'] = $comment; } if( $parse_printf && ( $format = $this->fsniff($msgid) ) ){ $entry['format'] = $format; } $index = $strings->pushMsgid( $key, $entry, $domain ); if( is_int($p) && isset($args[$p]) ){ $msgid_plural = $args[$p]; $entry = array( 'id' => '', 'source' => $msgid_plural, 'target' => '', 'plural' => 1, 'parent' => $index, ); if( false !== $parse_printf && ( $format = $this->fsniff($msgid_plural) ) ){ $entry['format'] = $format; } $strings->pushMsgidPlural( $key, $entry ); } return $index; } } abstract class LocoExtractor { private $rules; private $wp = array(); private $domain = ''; abstract public function tokenize( $src ); abstract public function extract( LocoExtracted $strings, LocoTokensInterface $tokens, $fileref = '' ); abstract protected function fsniff( $str ); abstract protected function decapse( $raw ); abstract protected function comment( $comment ); public function __construct( array $rules ){ $this->rules = $rules; } public function setDomain( $default ){ $this->domain = $default; return $this; } public function headerize( array $tags, $domain = '' ){ if( isset($this->wp[$domain]) ){ $this->wp[$domain] += $tags; } else { $this->wp[$domain] = $tags; } return $this; } protected function getHeaders(){ return $this->wp; } final public function extractSource( $src, $fileref ){ $strings = new LocoExtracted; $this->extract( $strings, $this->tokenize($src), $fileref ); return $strings; } public function rule( $s ){ return isset($this->rules[$s]) ? $this->rules[$s] : ''; } protected function push( LocoExtracted $strings, $rule, array $args, $comment = '', $ref = '' ){ $s = strpos( $rule, 's'); $p = strpos( $rule, 'p'); $c = strpos( $rule, 'c'); $d = strpos( $rule, 'd'); if( false === $s || ! isset($args[$s]) ){ return null; } $key = $args[$s]; if( ! is_string($key) ){ return null; } $msgid = $key; $entry = array( 'id' => '', 'source' => $msgid, 'target' => '', ); if( is_int($c) && isset($args[$c]) ){ $entry['context'] = $context = $args[$c]; $key .= "\0". $context; } else if( '' === $msgid ){ return null; } else { $context = null; } if( $ref ){ $entry['refs'] = $ref; } if( is_int($d) && array_key_exists($d,$args) ){ $domain = $args[$d]; if( is_null($domain) ){ $domain = ''; } } else if( '' === $this->domain ) { $domain = $strings->getDomain(); } else { $domain = $this->domain; } if( is_string($domain) && '' !== $domain ){ $entry['domain'] = $domain; $key .= "\1".$domain; } $parse_printf = true; if( $comment = $this->comment($comment) ){ if( preg_match('/^xgettext:\\s*([-a-z]+)-format\\s*/mi', $comment, $r, PREG_OFFSET_CAPTURE ) ){ $entry['format'] = $r[1][0]; $comment = trim( substr_replace( $comment,'', $r[0][1], strlen($r[0][0]) ) ); $parse_printf = ( 'no-' === substr($entry['format'],0,3) ) ? false : null; } if( preg_match('/^references?:( *.+:\\d+)*\\s*/mi', $comment, $r, PREG_OFFSET_CAPTURE ) ){ $entry['refs'] = trim($r[1][0],' '); $comment = trim( substr_replace( $comment, '', $r[0][1], strlen($r[0][0]) ) ); } $entry['notes'] = $comment; } if( $parse_printf && ( $format = $this->fsniff($msgid) ) ){ $entry['format'] = $format; } $index = $strings->pushMsgid( $key, $entry, $domain ); if( is_int($p) && isset($args[$p]) ){ $msgid_plural = $args[$p]; $entry = array( 'id' => '', 'source' => $msgid_plural, 'target' => '', 'plural' => 1, 'parent' => $index, ); if( false !== $parse_printf && ( $format = $this->fsniff($msgid_plural) ) ){ $entry['format'] = $format; } $strings->pushMsgidPlural( $key, $entry ); } return $index; } protected function utf8( $str ){ if( false === preg_match('//u',$str) ){ $str = mb_convert_encoding( $str, 'UTF-8', 'cp1252' ); } return $str; } }
class LocoPHPTokens implements LocoTokensInterface, Countable { private $i; private $tokens; private $skip_tokens = array(); private $literal_tokens = array(); public function __construct( array $tokens ){ $this->tokens = $tokens; $this->rewind(); } public function literal( array $a ){ foreach( $a as $t ){ $this->literal_tokens[ $t ] = 1; } return $this; } public function ignore( array $a ){ foreach( $a as $t ){ $this->skip_tokens[$t] = true; } return $this; } public function export(){ $arr = array(); $this->rewind(); while( $tok = $this->advance() ){ $arr[] = $tok; } return $arr; } public function advance(){ $tok = $this->current(); $this->next(); return $tok; } public function rewind(){ $this->i = ( false === reset($this->tokens) ? null : key($this->tokens) ); } public function valid(){ while( isset($this->i) ){ $tok = $this->tokens[$this->i]; if( array_key_exists( is_array($tok) ? $tok[0] : $tok, $this->skip_tokens ) ){ $this->next(); } else { return true; } } return false; } public function key(){ return $this->i; } public function next(){ $this->i = ( false === next($this->tokens) ? null : key($this->tokens) ); } public function current(){ if( ! $this->valid() ){ return false; } $tok = $this->tokens[$this->i]; if( is_array($tok) && isset($this->literal_tokens[$tok[0]]) ){ return $tok[1]; } return $tok; } public function __toString(){ $s = array(); foreach( $this as $token ){ $s[] = is_array($token) ? $token[1] : $token; } return implode('',$s); } public function count(){ return count($this->tokens); } } class LocoPHPTokens implements LocoTokensInterface, Countable { private $i; private $tokens; private $skip_tokens = array(); private $literal_tokens = array(); public function __construct( array $tokens ){ $this->tokens = $tokens; $this->rewind(); } public function literal( array $a ){ foreach( $a as $t ){ $this->literal_tokens[ $t ] = 1; } return $this; } public function ignore( array $a ){ foreach( $a as $t ){ $this->skip_tokens[$t] = true; } return $this; } public function export(){ $arr = array(); $this->rewind(); while( $tok = $this->advance() ){ $arr[] = $tok; } return $arr; } public function advance(){ $tok = $this->current(); $this->next(); return $tok; } public function rewind(){ $this->i = ( false === reset($this->tokens) ? null : key($this->tokens) ); } public function valid(){ while( isset($this->i) ){ $tok = $this->tokens[$this->i]; if( array_key_exists( is_array($tok) ? $tok[0] : $tok, $this->skip_tokens ) ){ $this->next(); } else { return true; } } return false; } public function key(){ return $this->i; } public function next(){ $this->i = ( false === next($this->tokens) ? null : key($this->tokens) ); } public function current(){ if( ! $this->valid() ){ return false; } $tok = $this->tokens[$this->i]; if( is_array($tok) && isset($this->literal_tokens[$tok[0]]) ){ return $tok[1]; } return $tok; } public function __toString(){ $s = array(); foreach( $this as $token ){ $s[] = is_array($token) ? $token[1] : $token; } return implode('',$s); } public function count(){ return count($this->tokens); } }
class LocoPHPEscapeParser extends LocoEscapeParser { public function __construct(){ parent::__construct( array( 'n' => "\n", 'r' => "\r", 't' => "\t", 'v' => "\x0B", 'f' => "\x0C", 'e' => "\x1B", '$' => '$', '\\' => '\\', '"' => '"', ) ); } protected function stripSlashes( $s ){ return preg_replace_callback('/\\\\(x[0-9A-Fa-f]{1,2}|[0-3]?[0-7]{1,2})/', array($this,'unescapeMatch'), $s, -1, $n ); } } class LocoPHPEscapeParser extends LocoEscapeParser { public function __construct(){ parent::__construct( array( 'n' => "\n", 'r' => "\r", 't' => "\t", 'v' => "\x0B", 'f' => "\x0C", 'e' => "\x1B", '$' => '$', '\\' => '\\', '"' => '"', ) ); } protected function stripSlashes( $s ){ return preg_replace_callback('/\\\\(x[0-9A-Fa-f]{1,2}|[0-3]?[0-7]{1,2})/', array($this,'unescapeMatch'), $s, -1, $n ); } }
function loco_unescape_php_string( $s ){ static $l; if( is_null($l) ) { $l = new LocoPHPEscapeParser; } return $l->unescape($s); } function loco_unescape_php_string( $s ){ static $l; if( is_null($l) ) { $l = new LocoPHPEscapeParser; } return $l->unescape($s); }
...@@ -35,7 +36,7 @@ function loco_parse_php_comment($comment){ $comment = trim( $comment,"/ \n\r\t" ...@@ -35,7 +36,7 @@ function loco_parse_php_comment($comment){ $comment = trim( $comment,"/ \n\r\t"
function loco_parse_wp_comment( $block ){ $header = array(); if( '*' === $block[1] ){ $junk = "\r\t/ *"; foreach( explode("\n", $block) as $line ){ if( false !== ( $i = strpos($line,':') ) ){ $key = substr($line,0,$i); $val = substr($line,++$i); $header[ trim($key,$junk) ] = trim($val,$junk); } } } return $header; } function loco_parse_wp_comment( $block ){ $header = array(); if( '*' === $block[1] ){ $junk = "\r\t/ *"; foreach( explode("\n", $block) as $line ){ if( false !== ( $i = strpos($line,':') ) ){ $key = substr($line,0,$i); $val = substr($line,++$i); $header[ trim($key,$junk) ] = trim($val,$junk); } } } return $header; }
function loco_sniff_printf( $s, $p, $limit = 0, $offset = 0 ){ $n = 0; while( is_string($s) && '' !== $s && false !== ( $i = strpos($s,'%',$offset) ) ){ if( 0 !== $i ){ $s = substr( $s, $i ); } if( preg_match( $p, $s, $r ) ){ $match = $r[0]; if( 0 < $n && isset($r[1]) && '' === $r[1] && '%' !== substr($match,-1) ){ return 0; } if( ++$n === $limit ){ break; } $offset = strlen($match); } else { return 0; } } return $n; } function loco_sniff_printf( $s, $p, $limit = 0, $offset = 0 ){ $n = 0; while( is_string($s) && '' !== $s && false !== ( $i = strpos($s,'%',$offset) ) ){ if( 0 !== $i ){ $s = substr( $s, $i ); } if( preg_match( $p, $s, $r ) ){ $match = $r[0]; if( 0 < $n && isset($r[1]) && '' === $r[1] && '%' !== substr($match,-1) ){ return 0; } if( ++$n === $limit ){ break; } $offset = strlen($match); } else { return 0; } } return $n; }
function loco_sniff_php_printf( $s, $limit = 0 ){ return loco_sniff_printf( $s, '/^%(?:[1-9]\\d*\\$)?(?:\'.|[-+0 ])*\\d*(?:\\.\\d+)?[suxXbcdeEfFgGo%]/', $limit ); } function loco_sniff_php_printf( $s, $limit = 0 ){ return loco_sniff_printf( $s, '/^%(?:[1-9]\\d*\\$)?(?:\'.|[-+0 ])*\\d*(?:\\.\\d+)?[suxXbcdeEfFgGo%]/', $limit ); }
class LocoPHPExtractor extends LocoExtractor { private $defs = array(); public function tokenize( $src ){ return new LocoPHPTokens( token_get_all($src) ); } public function decapse( $raw ){ return loco_decapse_php_string( $raw ); } public function fsniff( $str ){ return loco_sniff_php_printf($str) ? 'php' : ''; } protected function comment( $comment ){ $comment = loco_parse_php_comment($comment); $comment = preg_replace('/^translators:\\s+/mi', '', $comment ); return $comment; } public function define( $name, $value ){ if( is_string($value) ){ $this->defs[$name] = $value; } return $this; } public function extract( LocoExtracted $strings, LocoTokensInterface $tokens, $fileref = '' ){ $tokens->ignore( array(T_WHITESPACE) ); $n = 0; $depth = 0; $comment = ''; $narg = 0; $args = array(); $ref = ''; $rule = ''; $wp = $this->getHeaders(); $tokens->rewind(); while( $tok = $tokens->advance() ){ if( is_string($tok) ){ $s = $tok; $t = null; } else { $t = $tok[0]; $s = $tok[1]; } if( $depth ){ if( ')' === $s || ']' === $s ){ if( 0 === --$depth ){ if( $this->push( $strings, $rule, $args, $comment, $ref ) ){ $n++; } $comment = ''; } } else if( '(' === $s || '[' === $s ){ $depth++; $args[$narg] = null; } else if( 1 === $depth ){ if( ',' === $s ){ $narg++; } else if( T_CONSTANT_ENCAPSED_STRING === $t ){ $args[$narg] = $this->decapse($s); } else if( T_STRING === $t && array_key_exists($s,$this->defs) ){ $args[$narg] = $this->defs[$s]; } else { $args[$narg] = null; } } } else if( T_COMMENT === $t || T_DOC_COMMENT === $t ){ $was_header = false; if( 0 === $n ){ if( false !== strpos($s,'* @package') ){ $was_header = true; } if( $wp && ( $header = loco_parse_wp_comment($s) ) ){ foreach( $wp as $domain => $tags ){ foreach( array_intersect_key($header,$tags) as $tag => $source ){ $strings->pushMeta( $source, $tags[$tag], $domain ); $was_header = true; } } } } if( ! $was_header ) { $comment = $s; } } else if( T_STRING === $t && '(' === $tokens->advance() && ( $rule = $this->rule($s) ) ){ $ref = $fileref ? $fileref.':'.$tok[2]: ''; $depth = 1; $args = array(); $narg = 0; } else if( $comment ){ if( false === stripos($comment, 'translators:') && false === strpos($comment, 'xgettext:') ){ $comment = ''; } } } return $this; } } class LocoPHPExtractor extends LocoExtractor { private $defs = array(); public function tokenize( $src ){ return new LocoPHPTokens( token_get_all($src) ); } public function decapse( $raw ){ return loco_decapse_php_string( $raw ); } public function fsniff( $str ){ return loco_sniff_php_printf($str) ? 'php' : ''; } protected function comment( $comment ){ $comment = loco_parse_php_comment($comment); $comment = preg_replace('/^translators:\\s+/mi', '', $comment ); return $comment; } public function define( $name, $value ){ if( is_string($value) ){ $this->defs[$name] = $value; } return $this; } public function extract( LocoExtracted $strings, LocoTokensInterface $tokens, $fileref = '' ){ $tokens->ignore( array(T_WHITESPACE) ); $n = 0; $depth = 0; $comment = ''; $narg = 0; $args = array(); $ref = ''; $rule = ''; $wp = $this->getHeaders(); $tokens->rewind(); while( $tok = $tokens->advance() ){ if( is_string($tok) ){ $s = $tok; $t = null; } else { $t = $tok[0]; $s = $tok[1]; } if( $depth ){ if( ')' === $s || ']' === $s ){ if( 0 === --$depth ){ if( $this->push( $strings, $rule, $args, $comment, $ref ) ){ $n++; } $comment = ''; } } else if( '(' === $s || '[' === $s ){ $depth++; $args[$narg] = null; } else if( 1 === $depth ){ if( ',' === $s ){ $narg++; } else if( T_CONSTANT_ENCAPSED_STRING === $t ){ $s = self::utf8($s); $args[$narg] = $this->decapse($s); } else if( T_STRING === $t && array_key_exists($s,$this->defs) ){ $args[$narg] = $this->defs[$s]; } else { $args[$narg] = null; } } } else if( T_COMMENT === $t || T_DOC_COMMENT === $t ){ $was_header = false; $s = self::utf8($s); if( 0 === $n ){ if( false !== strpos($s,'* @package') ){ $was_header = true; } if( $wp && ( $header = loco_parse_wp_comment($s) ) ){ foreach( $wp as $domain => $tags ){ foreach( array_intersect_key($header,$tags) as $tag => $source ){ $strings->pushMeta( $source, $tags[$tag], $domain ); $was_header = true; } } } } if( ! $was_header ) { $comment = $s; } } else if( T_STRING === $t && '(' === $tokens->advance() && ( $rule = $this->rule($s) ) ){ $ref = $fileref ? $fileref.':'.$tok[2]: ''; $depth = 1; $args = array(); $narg = 0; } else if( $comment ){ if( false === stripos($comment, 'translators:') && false === strpos($comment, 'xgettext:') ){ $comment = ''; } } } return $this; } }
function loco_sniff_js_printf( $s, $limit = 0 ){ return loco_sniff_printf( $s, '/^%(?:[1-9]\\d*\\$)?\\+?(?:0|\'[^$])?-?\\d*(?:\\.\\d+)?[b-gijostTuvxX%]/', $limit ); } function loco_sniff_js_printf( $s, $limit = 0 ){ return loco_sniff_printf( $s, '/^%(?:[1-9]\\d*\\$)?\\+?(?:0|\'[^$])?-?\\d*(?:\\.\\d+)?[b-gijostTuvxX%]/', $limit ); }
class LocoJsExtractor extends LocoPHPExtractor { public function tokenize( $src ){ return new LocoJsTokens($src); } public function fsniff( $str ){ return loco_sniff_js_printf($str) ? 'javascript' : ''; } public function decapse( $encapsed ){ return LocoJsTokens::decapse($encapsed); } } class LocoJsExtractor extends LocoPHPExtractor { public function tokenize( $src ){ return new LocoJsTokens($src); } public function fsniff( $str ){ return loco_sniff_js_printf($str) ? 'javascript' : ''; } public function decapse( $encapsed ){ return LocoJsTokens::decapse($encapsed); } }
class LocoTwigExtractor extends LocoPHPExtractor { public function tokenize( $src ){ $src = '<?php '.preg_replace('/{#([^#]+)#}/su','/*\\1*/',$src); return parent::tokenize($src); } } class LocoTwigExtractor extends LocoPHPExtractor { public function tokenize( $src ){ $src = '<?php '.preg_replace('/{#([^#]+)#}/su','/*\\1*/',$src); return parent::tokenize($src); } }
...@@ -43,4 +44,5 @@ function loco_wp_extractor( $type = 'php' ){ static $rules = array( '__' => 'sd' ...@@ -43,4 +44,5 @@ function loco_wp_extractor( $type = 'php' ){ static $rules = array( '__' => 'sd'
function loco_print_percent( $n, $t ){ $s = loco_string_percent( (int) $n, (int) $t ); echo $s,'%'; return ''; } function loco_print_percent( $n, $t ){ $s = loco_string_percent( (int) $n, (int) $t ); echo $s,'%'; return ''; }
function loco_print_progress( $translated, $untranslated, $flagged ){ $total = $translated + $untranslated; $complete = loco_string_percent( $translated - $flagged, $total ); $class = 'progress'; if( ! $translated && ! $flagged ){ $class .= ' empty'; } else if( '100' === $complete ){ $class .= ' done'; } echo '<div class="',$class,'"><div class="t">'; if( $flagged ){ $s = loco_string_percent( $flagged, $total ); echo '<div class="bar f" style="width:',$s,'%">&nbsp;</div>'; } if( '0' === $complete ){ echo '&nbsp;'; } else { $class = 'bar p'; $p = (int) $complete; $class .= sprintf(' p-%u', 10*floor($p/10) ); $style = 'width:'.$complete.'%'; if( $flagged ){ $remain = 100.0 - (float) $s; $style .= '; max-width: '.sprintf('%s',$remain).'%'; } echo '<div class="',$class,'" style="'.$style.'">&nbsp;</div>'; } echo '</div><div class="l">',$complete,'%</div></div>'; return ''; } function loco_print_progress( $translated, $untranslated, $flagged ){ $total = $translated + $untranslated; $complete = loco_string_percent( $translated - $flagged, $total ); $class = 'progress'; if( ! $translated && ! $flagged ){ $class .= ' empty'; } else if( '100' === $complete ){ $class .= ' done'; } echo '<div class="',$class,'"><div class="t">'; if( $flagged ){ $s = loco_string_percent( $flagged, $total ); echo '<div class="bar f" style="width:',$s,'%">&nbsp;</div>'; } if( '0' === $complete ){ echo '&nbsp;'; } else { $class = 'bar p'; $p = (int) $complete; $class .= sprintf(' p-%u', 10*floor($p/10) ); $style = 'width:'.$complete.'%'; if( $flagged ){ $remain = 100.0 - (float) $s; $style .= '; max-width: '.sprintf('%s',$remain).'%'; } echo '<div class="',$class,'" style="'.$style.'">&nbsp;</div>'; } echo '</div><div class="l">',$complete,'%</div></div>'; return ''; }
function loco_string_percent( $n, $t ){ if( ! $t || ! $n ){ $s = '0'; } else if( $t === $n ){ $s = '100'; } else { $dp = 0; $n = 100 * $n / $t; if( $n > 99 ){ $s = number_format( min( $n, 99.9 ), ++$dp ); } else if( $n < 0.5 ){ $n = max( $n, 0.0001 ); do { $s = number_format( $n, ++$dp ); } while( preg_match('/^0\\.0+$/',$s) && $dp < 4 ); $s = substr($s,1); } else { $s = number_format( $n, $dp ); } } return $s; } function loco_string_percent( $n, $t ){ if( ! $t || ! $n ){ $s = '0'; } else if( $t === $n ){ $s = '100'; } else { $dp = 0; $n = 100 * $n / $t; if( $n > 99 ){ $s = number_format( min( $n, 99.9 ), ++$dp ); } else if( $n < 0.5 ){ $n = max( $n, 0.0001 ); do { $s = number_format( $n, ++$dp ); } while( preg_match('/^0\\.0+$/',$s) && $dp < 4 ); $s = substr($s,1); } else { $s = number_format( $n, $dp ); } } return $s; }
defined('T_FINALLY') || define('T_FINALLY',500); class LocoFuzzyMatcher implements Countable { private $pot = array(); private $po = array(); private $diff = array(); private $dmax = .20; public function count(){ return count($this->pot); } public function unmatched(){ return array_values($this->pot); } public function redundant(){ return array_values($this->po); } public function setFuzziness( $s ){ if( $this->po ){ throw new LogicException('Cannot setFuzziness() after calling match()'); } $this->dmax = (float) max( 0, min( (int) $s, 100 ) ) / 100; } public function add( $a ){ $source = isset($a['source']) ? (string) $a['source'] : ''; $context = isset($a['context']) ? (string) $a['context'] : ''; $this->pot[$source."\4".$context] = $a; } public function match( $a ) { $source = isset($a['source']) ? (string) $a['source'] : ''; $context = isset($a['context']) ? (string) $a['context'] : ''; $old = $source."\4".$context; if( isset($this->pot[$old]) ){ $new = $this->pot[$old]; unset($this->pot[$old]); return $new; } $this->po[$old] = $a; $target = isset($a['target']) ? (string) $a['target'] : ''; $comment = isset($a['comment']) ? (string) $a['comment'] : ''; if( '' === $target && '' === $comment ){ return null; } if( 0 < $this->dmax ){ foreach( $this->pot as $new => $_ ){ $dist = $this->distance($old,$new); if( -1 !== $dist ){ $this->diff[] = array( $old, $new, $dist ); } } } return null; } private function distance( $a, $b ){ $a = strtolower($a); $b = strtolower($b); if( $a === $b ){ return 0; } $lenA = strlen($a); $lenB = strlen($b); $lenDiff = abs($lenA-$lenB); $max = min($lenA,$lenB) + $lenDiff; $max = (int) ceil( $this->dmax * $max ); if( $max < $lenDiff ) { return -1; } $len = max($lenA,$lenB); if( $len < 256 ){ $d = levenshtein($a,$b); return $d > $max ? -1 : $d; } $d = 0; for( $i = 0; $i < $len; $i+=$max ){ $aa = substr($a,$i,$max); $bb = substr($b,$i,$max); $d += levenshtein($aa,$bb); if( $d > $max ){ return -1; } } return $d; } public function getFuzzyMatches(){ $pairs = array(); usort( $this->diff, array(__CLASS__,'compareDistance') ); foreach( $this->diff as $pair ){ list($old,$new) = $pair; if( ! array_key_exists($new,$this->pot) || ! array_key_exists($old,$this->po) ){ continue; } $pairs[] = array( $this->po[$old], $this->pot[$new], ); unset($this->po[$old]); unset($this->pot[$new]); if( ! $this->po || ! $this->pot ){ break; } } $this->diff = array(); return $pairs; } private static function compareDistance( array $a, array $b ){ return $a[2] - $b[2]; } }
defined('T_FINALLY') || define('T_FINALLY',500); loco_check_extension('mbstring');
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
/** /**
* Compiled data. Do not edit. * Compiled data. Do not edit.
*/ */
return array('af'=>array(0=>'Afrikaans',1=>'Afrikaans'),'ar'=>array(0=>'Arabic',1=>'العربية'),'ary'=>array(0=>'Moroccan Arabic',1=>'العربية المغربية'),'as'=>array(0=>'Assamese',1=>'অসমীয়া'),'az'=>array(0=>'Azerbaijani',1=>'Azərbaycan dili'),'azb'=>array(0=>'South Azerbaijani',1=>'گؤنئی آذربایجان'),'bel'=>array(0=>'Belarusian',1=>'Беларуская мова'),'bg_BG'=>array(0=>'Bulgarian',1=>'Български'),'bn_BD'=>array(0=>'Bengali (Bangladesh)',1=>'বাংলা'),'bo'=>array(0=>'Tibetan',1=>'བོད་ཡིག'),'bs_BA'=>array(0=>'Bosnian',1=>'Bosanski'),'ca'=>array(0=>'Catalan',1=>'Català'),'ceb'=>array(0=>'Cebuano',1=>'Cebuano'),'cs_CZ'=>array(0=>'Czech',1=>'Čeština'),'cy'=>array(0=>'Welsh',1=>'Cymraeg'),'da_DK'=>array(0=>'Danish',1=>'Dansk'),'de_DE_formal'=>array(0=>'German (Formal)',1=>'Deutsch (Sie)'),'de_CH_informal'=>array(0=>'German (Switzerland, Informal)',1=>'Deutsch (Schweiz, Du)'),'de_DE'=>array(0=>'German',1=>'Deutsch'),'de_CH'=>array(0=>'German (Switzerland)',1=>'Deutsch (Schweiz)'),'dzo'=>array(0=>'Dzongkha',1=>'རྫོང་ཁ'),'el'=>array(0=>'Greek',1=>'Ελληνικά'),'en_GB'=>array(0=>'English (UK)',1=>'English (UK)'),'en_CA'=>array(0=>'English (Canada)',1=>'English (Canada)'),'en_NZ'=>array(0=>'English (New Zealand)',1=>'English (New Zealand)'),'en_ZA'=>array(0=>'English (South Africa)',1=>'English (South Africa)'),'en_AU'=>array(0=>'English (Australia)',1=>'English (Australia)'),'eo'=>array(0=>'Esperanto',1=>'Esperanto'),'es_GT'=>array(0=>'Spanish (Guatemala)',1=>'Español de Guatemala'),'es_AR'=>array(0=>'Spanish (Argentina)',1=>'Español de Argentina'),'es_CL'=>array(0=>'Spanish (Chile)',1=>'Español de Chile'),'es_VE'=>array(0=>'Spanish (Venezuela)',1=>'Español de Venezuela'),'es_CO'=>array(0=>'Spanish (Colombia)',1=>'Español de Colombia'),'es_MX'=>array(0=>'Spanish (Mexico)',1=>'Español de México'),'es_CR'=>array(0=>'Spanish (Costa Rica)',1=>'Español de Costa Rica'),'es_PE'=>array(0=>'Spanish (Peru)',1=>'Español de Perú'),'es_ES'=>array(0=>'Spanish (Spain)',1=>'Español'),'et'=>array(0=>'Estonian',1=>'Eesti'),'eu'=>array(0=>'Basque',1=>'Euskara'),'fa_IR'=>array(0=>'Persian',1=>'فارسی'),'fi'=>array(0=>'Finnish',1=>'Suomi'),'fr_BE'=>array(0=>'French (Belgium)',1=>'Français de Belgique'),'fr_CA'=>array(0=>'French (Canada)',1=>'Français du Canada'),'fr_FR'=>array(0=>'French (France)',1=>'Français'),'fur'=>array(0=>'Friulian',1=>'Friulian'),'gd'=>array(0=>'Scottish Gaelic',1=>'Gàidhlig'),'gl_ES'=>array(0=>'Galician',1=>'Galego'),'gu'=>array(0=>'Gujarati',1=>'ગુજરાતી'),'haz'=>array(0=>'Hazaragi',1=>'هزاره گی'),'he_IL'=>array(0=>'Hebrew',1=>'עִבְרִית'),'hi_IN'=>array(0=>'Hindi',1=>'हिन्दी'),'hr'=>array(0=>'Croatian',1=>'Hrvatski'),'hu_HU'=>array(0=>'Hungarian',1=>'Magyar'),'hy'=>array(0=>'Armenian',1=>'Հայերեն'),'id_ID'=>array(0=>'Indonesian',1=>'Bahasa Indonesia'),'is_IS'=>array(0=>'Icelandic',1=>'Íslenska'),'it_IT'=>array(0=>'Italian',1=>'Italiano'),'ja'=>array(0=>'Japanese',1=>'日本語'),'jv_ID'=>array(0=>'Javanese',1=>'Basa Jawa'),'ka_GE'=>array(0=>'Georgian',1=>'ქართული'),'kab'=>array(0=>'Kabyle',1=>'Taqbaylit'),'kk'=>array(0=>'Kazakh',1=>'Қазақ тілі'),'km'=>array(0=>'Khmer',1=>'ភាសាខ្មែរ'),'ko_KR'=>array(0=>'Korean',1=>'한국어'),'ckb'=>array(0=>'Kurdish (Sorani)',1=>'كوردی‎'),'lo'=>array(0=>'Lao',1=>'ພາສາລາວ'),'lt_LT'=>array(0=>'Lithuanian',1=>'Lietuvių kalba'),'lv'=>array(0=>'Latvian',1=>'Latviešu valoda'),'mk_MK'=>array(0=>'Macedonian',1=>'Македонски јазик'),'ml_IN'=>array(0=>'Malayalam',1=>'മലയാളം'),'mn'=>array(0=>'Mongolian',1=>'Монгол'),'mr'=>array(0=>'Marathi',1=>'मराठी'),'ms_MY'=>array(0=>'Malay',1=>'Bahasa Melayu'),'my_MM'=>array(0=>'Myanmar (Burmese)',1=>'ဗမာစာ'),'nb_NO'=>array(0=>'Norwegian (Bokmål)',1=>'Norsk bokmål'),'ne_NP'=>array(0=>'Nepali',1=>'नेपाली'),'nl_NL_formal'=>array(0=>'Dutch (Formal)',1=>'Nederlands (Formeel)'),'nl_NL'=>array(0=>'Dutch',1=>'Nederlands'),'nl_BE'=>array(0=>'Dutch (Belgium)',1=>'Nederlands (België)'),'nn_NO'=>array(0=>'Norwegian (Nynorsk)',1=>'Norsk nynorsk'),'oci'=>array(0=>'Occitan',1=>'Occitan'),'pa_IN'=>array(0=>'Punjabi',1=>'ਪੰਜਾਬੀ'),'pl_PL'=>array(0=>'Polish',1=>'Polski'),'ps'=>array(0=>'Pashto',1=>'پښتو'),'pt_BR'=>array(0=>'Portuguese (Brazil)',1=>'Português do Brasil'),'pt_PT'=>array(0=>'Portuguese (Portugal)',1=>'Português'),'pt_PT_ao90'=>array(0=>'Portuguese (Portugal, AO90)',1=>'Português (AO90)'),'rhg'=>array(0=>'Rohingya',1=>'Ruáinga'),'ro_RO'=>array(0=>'Romanian',1=>'Română'),'ru_RU'=>array(0=>'Russian',1=>'Русский'),'sah'=>array(0=>'Sakha',1=>'Сахалыы'),'si_LK'=>array(0=>'Sinhala',1=>'සිංහල'),'sk_SK'=>array(0=>'Slovak',1=>'Slovenčina'),'sl_SI'=>array(0=>'Slovenian',1=>'Slovenščina'),'sq'=>array(0=>'Albanian',1=>'Shqip'),'sr_RS'=>array(0=>'Serbian',1=>'Српски језик'),'sv_SE'=>array(0=>'Swedish',1=>'Svenska'),'szl'=>array(0=>'Silesian',1=>'Ślōnskŏ gŏdka'),'ta_IN'=>array(0=>'Tamil',1=>'தமிழ்'),'te'=>array(0=>'Telugu',1=>'తెలుగు'),'th'=>array(0=>'Thai',1=>'ไทย'),'tl'=>array(0=>'Tagalog',1=>'Tagalog'),'tr_TR'=>array(0=>'Turkish',1=>'Türkçe'),'tt_RU'=>array(0=>'Tatar',1=>'Татар теле'),'tah'=>array(0=>'Tahitian',1=>'Reo Tahiti'),'ug_CN'=>array(0=>'Uighur',1=>'ئۇيغۇرچە'),'uk'=>array(0=>'Ukrainian',1=>'Українська'),'ur'=>array(0=>'Urdu',1=>'اردو'),'uz_UZ'=>array(0=>'Uzbek',1=>'O‘zbekcha'),'vi'=>array(0=>'Vietnamese',1=>'Tiếng Việt'),'zh_CN'=>array(0=>'Chinese (China)',1=>'简体中文'),'zh_TW'=>array(0=>'Chinese (Taiwan)',1=>'繁體中文'),'zh_HK'=>array(0=>'Chinese (Hong Kong)',1=>'香港中文版 ')); return array('af'=>array(0=>'Afrikaans',1=>'Afrikaans'),'ar'=>array(0=>'Arabic',1=>'العربية'),'ary'=>array(0=>'Moroccan Arabic',1=>'العربية المغربية'),'as'=>array(0=>'Assamese',1=>'অসমীয়া'),'az'=>array(0=>'Azerbaijani',1=>'Azərbaycan dili'),'azb'=>array(0=>'South Azerbaijani',1=>'گؤنئی آذربایجان'),'bel'=>array(0=>'Belarusian',1=>'Беларуская мова'),'bg_BG'=>array(0=>'Bulgarian',1=>'Български'),'bn_BD'=>array(0=>'Bengali (Bangladesh)',1=>'বাংলা'),'bo'=>array(0=>'Tibetan',1=>'བོད་ཡིག'),'bs_BA'=>array(0=>'Bosnian',1=>'Bosanski'),'ca'=>array(0=>'Catalan',1=>'Català'),'ceb'=>array(0=>'Cebuano',1=>'Cebuano'),'cs_CZ'=>array(0=>'Czech',1=>'Čeština'),'cy'=>array(0=>'Welsh',1=>'Cymraeg'),'da_DK'=>array(0=>'Danish',1=>'Dansk'),'de_DE'=>array(0=>'German',1=>'Deutsch'),'de_DE_formal'=>array(0=>'German (Formal)',1=>'Deutsch (Sie)'),'de_CH_informal'=>array(0=>'German (Switzerland, Informal)',1=>'Deutsch (Schweiz, Du)'),'de_CH'=>array(0=>'German (Switzerland)',1=>'Deutsch (Schweiz)'),'dzo'=>array(0=>'Dzongkha',1=>'རྫོང་ཁ'),'el'=>array(0=>'Greek',1=>'Ελληνικά'),'en_NZ'=>array(0=>'English (New Zealand)',1=>'English (New Zealand)'),'en_ZA'=>array(0=>'English (South Africa)',1=>'English (South Africa)'),'en_GB'=>array(0=>'English (UK)',1=>'English (UK)'),'en_CA'=>array(0=>'English (Canada)',1=>'English (Canada)'),'en_AU'=>array(0=>'English (Australia)',1=>'English (Australia)'),'eo'=>array(0=>'Esperanto',1=>'Esperanto'),'es_CO'=>array(0=>'Spanish (Colombia)',1=>'Español de Colombia'),'es_AR'=>array(0=>'Spanish (Argentina)',1=>'Español de Argentina'),'es_VE'=>array(0=>'Spanish (Venezuela)',1=>'Español de Venezuela'),'es_MX'=>array(0=>'Spanish (Mexico)',1=>'Español de México'),'es_ES'=>array(0=>'Spanish (Spain)',1=>'Español'),'es_CL'=>array(0=>'Spanish (Chile)',1=>'Español de Chile'),'es_CR'=>array(0=>'Spanish (Costa Rica)',1=>'Español de Costa Rica'),'es_PE'=>array(0=>'Spanish (Peru)',1=>'Español de Perú'),'es_GT'=>array(0=>'Spanish (Guatemala)',1=>'Español de Guatemala'),'et'=>array(0=>'Estonian',1=>'Eesti'),'eu'=>array(0=>'Basque',1=>'Euskara'),'fa_IR'=>array(0=>'Persian',1=>'فارسی'),'fi'=>array(0=>'Finnish',1=>'Suomi'),'fr_FR'=>array(0=>'French (France)',1=>'Français'),'fr_CA'=>array(0=>'French (Canada)',1=>'Français du Canada'),'fr_BE'=>array(0=>'French (Belgium)',1=>'Français de Belgique'),'fur'=>array(0=>'Friulian',1=>'Friulian'),'gd'=>array(0=>'Scottish Gaelic',1=>'Gàidhlig'),'gl_ES'=>array(0=>'Galician',1=>'Galego'),'gu'=>array(0=>'Gujarati',1=>'ગુજરાતી'),'haz'=>array(0=>'Hazaragi',1=>'هزاره گی'),'he_IL'=>array(0=>'Hebrew',1=>'עִבְרִית'),'hi_IN'=>array(0=>'Hindi',1=>'हिन्दी'),'hr'=>array(0=>'Croatian',1=>'Hrvatski'),'hu_HU'=>array(0=>'Hungarian',1=>'Magyar'),'hy'=>array(0=>'Armenian',1=>'Հայերեն'),'id_ID'=>array(0=>'Indonesian',1=>'Bahasa Indonesia'),'is_IS'=>array(0=>'Icelandic',1=>'Íslenska'),'it_IT'=>array(0=>'Italian',1=>'Italiano'),'ja'=>array(0=>'Japanese',1=>'日本語'),'jv_ID'=>array(0=>'Javanese',1=>'Basa Jawa'),'ka_GE'=>array(0=>'Georgian',1=>'ქართული'),'kab'=>array(0=>'Kabyle',1=>'Taqbaylit'),'kk'=>array(0=>'Kazakh',1=>'Қазақ тілі'),'km'=>array(0=>'Khmer',1=>'ភាសាខ្មែរ'),'ko_KR'=>array(0=>'Korean',1=>'한국어'),'ckb'=>array(0=>'Kurdish (Sorani)',1=>'كوردی‎'),'lo'=>array(0=>'Lao',1=>'ພາສາລາວ'),'lt_LT'=>array(0=>'Lithuanian',1=>'Lietuvių kalba'),'lv'=>array(0=>'Latvian',1=>'Latviešu valoda'),'mk_MK'=>array(0=>'Macedonian',1=>'Македонски јазик'),'ml_IN'=>array(0=>'Malayalam',1=>'മലയാളം'),'mn'=>array(0=>'Mongolian',1=>'Монгол'),'mr'=>array(0=>'Marathi',1=>'मराठी'),'ms_MY'=>array(0=>'Malay',1=>'Bahasa Melayu'),'my_MM'=>array(0=>'Myanmar (Burmese)',1=>'ဗမာစာ'),'nb_NO'=>array(0=>'Norwegian (Bokmål)',1=>'Norsk bokmål'),'ne_NP'=>array(0=>'Nepali',1=>'नेपाली'),'nl_BE'=>array(0=>'Dutch (Belgium)',1=>'Nederlands (België)'),'nl_NL_formal'=>array(0=>'Dutch (Formal)',1=>'Nederlands (Formeel)'),'nl_NL'=>array(0=>'Dutch',1=>'Nederlands'),'nn_NO'=>array(0=>'Norwegian (Nynorsk)',1=>'Norsk nynorsk'),'oci'=>array(0=>'Occitan',1=>'Occitan'),'pa_IN'=>array(0=>'Punjabi',1=>'ਪੰਜਾਬੀ'),'pl_PL'=>array(0=>'Polish',1=>'Polski'),'ps'=>array(0=>'Pashto',1=>'پښتو'),'pt_BR'=>array(0=>'Portuguese (Brazil)',1=>'Português do Brasil'),'pt_PT'=>array(0=>'Portuguese (Portugal)',1=>'Português'),'pt_PT_ao90'=>array(0=>'Portuguese (Portugal, AO90)',1=>'Português (AO90)'),'rhg'=>array(0=>'Rohingya',1=>'Ruáinga'),'ro_RO'=>array(0=>'Romanian',1=>'Română'),'ru_RU'=>array(0=>'Russian',1=>'Русский'),'sah'=>array(0=>'Sakha',1=>'Сахалыы'),'si_LK'=>array(0=>'Sinhala',1=>'සිංහල'),'sk_SK'=>array(0=>'Slovak',1=>'Slovenčina'),'sl_SI'=>array(0=>'Slovenian',1=>'Slovenščina'),'sq'=>array(0=>'Albanian',1=>'Shqip'),'sr_RS'=>array(0=>'Serbian',1=>'Српски језик'),'sv_SE'=>array(0=>'Swedish',1=>'Svenska'),'szl'=>array(0=>'Silesian',1=>'Ślōnskŏ gŏdka'),'ta_IN'=>array(0=>'Tamil',1=>'தமிழ்'),'te'=>array(0=>'Telugu',1=>'తెలుగు'),'th'=>array(0=>'Thai',1=>'ไทย'),'tl'=>array(0=>'Tagalog',1=>'Tagalog'),'tr_TR'=>array(0=>'Turkish',1=>'Türkçe'),'tt_RU'=>array(0=>'Tatar',1=>'Татар теле'),'tah'=>array(0=>'Tahitian',1=>'Reo Tahiti'),'ug_CN'=>array(0=>'Uighur',1=>'ئۇيغۇرچە'),'uk'=>array(0=>'Ukrainian',1=>'Українська'),'ur'=>array(0=>'Urdu',1=>'اردو'),'uz_UZ'=>array(0=>'Uzbek',1=>'O‘zbekcha'),'vi'=>array(0=>'Vietnamese',1=>'Tiếng Việt'),'zh_CN'=>array(0=>'Chinese (China)',1=>'简体中文'),'zh_TW'=>array(0=>'Chinese (Taiwan)',1=>'繁體中文'),'zh_HK'=>array(0=>'Chinese (Hong Kong)',1=>'香港中文版 '));
...@@ -4,7 +4,7 @@ Plugin Name: Loco Translate ...@@ -4,7 +4,7 @@ Plugin Name: Loco Translate
Plugin URI: https://wordpress.org/plugins/loco-translate/ Plugin URI: https://wordpress.org/plugins/loco-translate/
Description: Translate themes and plugins directly in WordPress Description: Translate themes and plugins directly in WordPress
Author: Tim Whitlock Author: Tim Whitlock
Version: 2.4.4 Version: 2.4.5
Author URI: https://localise.biz/wordpress/plugin Author URI: https://localise.biz/wordpress/plugin
Text Domain: loco-translate Text Domain: loco-translate
Domain Path: /languages/ Domain Path: /languages/
...@@ -30,7 +30,7 @@ function loco_plugin_file(){ ...@@ -30,7 +30,7 @@ function loco_plugin_file(){
* @return string * @return string
*/ */
function loco_plugin_version(){ function loco_plugin_version(){
return '2.4.4'; return '2.4.5';
} }
...@@ -132,17 +132,17 @@ function loco_require_lib( $path ){ ...@@ -132,17 +132,17 @@ function loco_require_lib( $path ){
*/ */
function loco_check_extension( $name ) { function loco_check_extension( $name ) {
static $cache = array(); static $cache = array();
if ( ! isset( $cache[$name] ) ) { if( ! array_key_exists($name,$cache) ) {
if ( extension_loaded($name) ) { if( extension_loaded($name) ){
$cache[ $name ] = true; $cache[$name] = true;
} }
else { else {
Loco_error_AdminNotices::warn( sprintf( __('Loco requires the "%s" PHP extension. Ask your hosting provider to install it','loco-translate'), $name ) ); Loco_error_AdminNotices::warn( sprintf( __('Loco Translate requires the "%s" PHP extension. Ask your hosting provider to install it','loco-translate'), $name ) );
$class = 'Loco_compat_'.ucfirst($name).'Extension.php'; $class = 'Loco_compat_'.ucfirst($name).'Extension.php';
$cache[$name] = class_exists($class); $cache[$name] = class_exists($class);
} }
} }
return $cache[ $name ]; return $cache[$name];
} }
...@@ -201,6 +201,12 @@ try { ...@@ -201,6 +201,12 @@ try {
if ( is_admin() ) { if ( is_admin() ) {
new Loco_hooks_AdminHooks; new Loco_hooks_AdminHooks;
} }
// enable wp cli commands
if( class_exists('WP_CLI',false) ) {
WP_CLI::add_command('loco','Loco_cli_Commands');
}
} }
catch( Exception $e ){ // PHP5+ catch( Exception $e ){ // PHP5+
trigger_error(sprintf('[Loco.fatal] %s in %s:%u',$e->getMessage(), $e->getFile(), $e->getLine() ),E_USER_NOTICE); trigger_error(sprintf('[Loco.fatal] %s in %s:%u',$e->getMessage(), $e->getFile(), $e->getLine() ),E_USER_NOTICE);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
#loco-editor{border:solid 1px #ccc}#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2.gif?v=2.4.4);background-repeat:no-repeat;min-height:16px}#loco-editor ._ajax_loader_f2x4{background:transparent url(../img/ajax-loader-f2-x4.gif?v=2.4.4) 0 0 no-repeat;min-height:75px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc.gif?v=2.4.4);background-repeat:no-repeat;min-height:16px}@media only screen and (-webkit-min-device-pixel-ratio: 2),only screen and (min--moz-device-pixel-ratio: 2),only screen and (-o-min-device-pixel-ratio: 2/1),only screen and (min-device-pixel-ratio: 2),only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx){#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2-x2.gif?v=2.4.4);background-size:16px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc-x2.gif?v=2.4.4);background-size:16px}}#loco-editor ._green_glow_inner,#loco-editor .is-editable>.wg-content>textarea:focus,#loco-editor .is-editable>.wg-content.has-focus .ace_scroller,#loco-editor .is-editable>.wg-content.has-focus .wysihtml-editor,#loco-editor .is-editable>.wg-content.has-focus .mce-content-body{-webkit-box-shadow:inset 0 0 10px 0 #3db63d;-moz-box-shadow:inset 0 0 10px 0 #3db63d;box-shadow:inset 0 0 10px 0 #3db63d}#loco-editor ._green_glow_outer{-webkit-box-shadow:0 0 .5em 0 #3db63d;-moz-box-shadow:0 0 .5em 0 #3db63d;box-shadow:0 0 .5em 0 #3db63d}#loco-editor .loco-font,#loco-editor .is-table .wg-thead .wg-sortable>header:after{font-family:"loco";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#loco-editor div.ta-mirror{position:absolute;top:0;border:solid 1px transparent;color:transparent;padding:.4em .6em;pointer-events:none}#loco-editor div.ta-mirror span{position:relative}#loco-editor div.ta-mirror span:after{color:#ccc;white-space:pre;display:inline-block;position:absolute;top:0;line-height:normal}#loco-editor div.ta-mirror .crlf:after{content:"¬"}#loco-editor div.ta-mirror .eof:after{content:"¶"}#loco-editor div.ta-mirror .x20:after{content:"·";color:#aaa}#loco-editor div.ta-mirror .x9:after{content:"⟶"}#loco-editor div.ta-mirror,#loco-editor .has-mirror textarea{white-space:pre-wrap;word-wrap:break-word;word-spacing:0px}#loco-editor .has-mirror ::placeholder{color:transparent}#loco-editor .has-mirror ::-webkit-input-placeholder{color:transparent}#loco-editor .has-mirror :-moz-placeholder{color:transparent;opacity:1}#loco-editor .has-mirror ::-moz-placeholder{color:transparent;opacity:1}#loco-editor .has-mirror :-ms-input-placeholder{color:transparent}#loco-editor .has-mirror .ielt10 .placeheld{color:transparent}#loco-editor div.ta-mirror{left:0;text-align:left}#loco-editor div.ta-mirror span:after{left:0}#loco-editor div.ta-mirror .eol:after{padding-left:.2em}#loco-editor [dir=RTL] div.ta-mirror{left:auto;right:0;text-align:right}#loco-editor [dir=RTL] div.ta-mirror span:after{right:0}#loco-editor [dir=RTL] div.ta-mirror .eol:after{padding-left:0;padding-right:.2em}#loco-editor .has-proxy>textarea{display:none !important}#loco-editor .has-proxy .ace_editor{height:100%;font-size:13px !important;line-height:1.4 !important}#loco-editor .has-proxy .ace_editor .ace_marker-layer .ace_bracket{display:none}#loco-editor .has-proxy .ace_print-margin{display:none}#loco-editor .ace_printf{color:#b90690;background-color:#edf1be}#loco-editor .ace_locked{color:gray}#loco-editor .ace_icu-quoted{color:gray}#loco-editor .ace_icu{color:#697eb9}#loco-editor .ace_icu.ace_name{color:#b90600}#loco-editor .resizer{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0 0 6px 0;background:#f0f0f0 url(../img/wg/splity.png?v=2.4.4) center bottom no-repeat;border:1px solid #ddd;overflow:hidden;cursor:move;cursor:row-resize;cursor:s-resize}#loco-editor .resizer>*{height:100%;border:none}#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2.gif?v=2.4.4);background-repeat:no-repeat;min-height:16px}#loco-editor ._ajax_loader_f2x4{background:transparent url(../img/ajax-loader-f2-x4.gif?v=2.4.4) 0 0 no-repeat;min-height:75px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc.gif?v=2.4.4);background-repeat:no-repeat;min-height:16px}@media only screen and (-webkit-min-device-pixel-ratio: 2),only screen and (min--moz-device-pixel-ratio: 2),only screen and (-o-min-device-pixel-ratio: 2/1),only screen and (min-device-pixel-ratio: 2),only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx){#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2-x2.gif?v=2.4.4);background-size:16px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc-x2.gif?v=2.4.4);background-size:16px}}#loco-editor ._green_glow_inner,#loco-editor .is-editable>.wg-content>textarea:focus,#loco-editor .is-editable>.wg-content.has-focus .ace_scroller,#loco-editor .is-editable>.wg-content.has-focus .wysihtml-editor,#loco-editor .is-editable>.wg-content.has-focus .mce-content-body{-webkit-box-shadow:inset 0 0 10px 0 #3db63d;-moz-box-shadow:inset 0 0 10px 0 #3db63d;box-shadow:inset 0 0 10px 0 #3db63d}#loco-editor ._green_glow_outer{-webkit-box-shadow:0 0 .5em 0 #3db63d;-moz-box-shadow:0 0 .5em 0 #3db63d;box-shadow:0 0 .5em 0 #3db63d}#loco-editor .loco-font,#loco-editor .is-table .wg-thead .wg-sortable>header:after{font-family:"loco";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#loco-editor .wg-cell,#loco-editor .wg-cell>div{clear:both;position:relative;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;outline:none}#loco-editor .wg-cell{left:0;top:0;padding:0;margin:0;overflow:hidden}#loco-editor .wg-split{background:#eee}#loco-editor .wg-body:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0}#loco-editor .wg-split-x>div>.not-first>*{margin-left:6px}#loco-editor .wg-split-y>div>.not-first>*{margin-top:6px}#loco-editor .wg-split>div>.has-title .wg-content{margin-top:0}#loco-editor .wg-split-x>div>.wg-cell{float:left;clear:none;height:100%}#loco-editor .wg-split-x>div{cursor:move;cursor:ew-resize;cursor:col-resize}#loco-editor .wg-split>div>.not-first:before{display:block;position:absolute;overflow:hidden;content:" "}#loco-editor .wg-split-x>div>.not-first:before{width:6px;height:100%;background:transparent url(../img/wg/splitx.png?v=2.4.4) center center no-repeat}#loco-editor .wg-split-y>div{cursor:move;cursor:ns-resize;cursor:row-resize}#loco-editor .wg-split-y>div>.not-first:before{height:6px;width:100%;background:transparent url(../img/wg/splity.png?v=2.4.4) center center no-repeat}#loco-editor .wg-split>div.locked{cursor:default}#loco-editor .wg-split-x>div.locked>.not-first>*{margin-left:0px}#loco-editor .wg-split-y>div.locked>.not-first>*{margin-top:0px}#loco-editor .wg-split>div.locked>.not-first:before{display:none}#loco-editor .has-title>header{background:#e2e2e2;cursor:default !important;margin:0;white-space:nowrap}#loco-editor .wg-content{background:#fff;cursor:default;padding:4px 6px;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#loco-editor .wg-toolbar{top:0;right:0;margin-top:6px;position:absolute}#loco-editor .wg-toolbar>span{color:#fff;background:#000;display:block;padding:0 6px;cursor:default !important}#loco-editor .wg-toolbar>span:active{color:#000;background-color:#fff}#loco-editor .wg-content,#loco-editor .wg-tbody>div{overflow:scroll;overflow-x:hidden;overflow-y:auto}#loco-editor .is-table{background-color:#fff}#loco-editor .is-table .wg-thead .has-title>header{font-weight:normal;background:transparent;padding:4px 0;margin:0 0 0 10px}#loco-editor .is-table .wg-thead>div>.not-first:before{background-position:center center}#loco-editor .is-table .wg-thead{background:#e2e2e2;border-bottom:solid 1px #ccc}#loco-editor .is-table .wg-tbody{background-image:url(data:image/gif;base64,R0lGODlhAQAsAIABAPz8/P///yH5BAEAAAEALAAAAAABACwAAAIIjI+pAe0PIygAOw==);position:relative}#loco-editor .is-table .wg-cols>div{float:left;clear:none}#loco-editor .is-table .wg-cols>div>div{white-space:nowrap;line-height:1.7em;padding-left:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis;-ms-text-overflow:ellipsis;background-color:#fff}#loco-editor .is-table .wg-cols>div>div:nth-child(even){background-color:#f7f7f7}#loco-editor .is-table .wg-cols>div>div.selected{background-color:#3db63d;color:#fff}#loco-editor .is-table .wg-cols>div>div.selected::selection{background-color:#fff;color:#000}#loco-editor .is-table .wg-cols>div:first-child>div{padding-left:4px}#loco-editor .is-table .wg-dead{clear:both}#loco-editor .is-table .wg-thead .wg-sortable>header{cursor:pointer !important}#loco-editor .is-table .wg-thead .wg-sortable>header:after{padding:0 0 0 5px;color:#999}#loco-editor .is-table .wg-thead .wg-sortable.wg-asc>header:after{content:"▲"}#loco-editor .is-table .wg-thead .wg-sortable.wg-desc>header:after{content:"▼"}#loco-editor .is-table .wg-thead .wg-sortable:hover>header:after{color:#000}#loco-editor .is-field>.wg-content{cursor:text;padding:0;line-height:normal;overflow:hidden;overflow-y:hidden}#loco-editor .is-field>.wg-content>div,#loco-editor .is-field>.wg-content>textarea{font-size:14px;line-height:1.4;border:1px solid #ddd;width:100%;height:100%;padding:8px 10px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}#loco-editor .is-field>.wg-content textarea{resize:none;overflow:auto;display:block}#loco-editor .is-field>.wg-content>.ace_editor{padding:0;border-width:0}#loco-editor .is-field>.wg-content>div[contenteditable]{overflow:scroll;overflow-x:hidden;overflow-y:auto}#loco-editor .is-readonly>.wg-content{cursor:default}#loco-editor .is-readonly>.wg-content>div,#loco-editor .is-readonly>.wg-content>textarea,#loco-editor .is-readonly>.wg-content>textarea[readonly]{background:#f8f8f8;text-shadow:0 1px #fff;color:inherit}#loco-editor .is-readonly>.wg-content .ace_scroller{cursor:default;background:#f8f8f8}#loco-editor .is-readonly>.wg-content .ace_cursor-layer{display:none}#loco-editor .is-readonly>.wg-content>textarea[readonly]{cursor:default}#loco-editor .is-editable>.wg-content[dir=RTL] .ace_editor .ace_line{direction:ltr;unicode-bidi:bidi-override}#loco-editor .wg-split-x>nav.wg-tabs{white-space:nowrap;text-align:center;cursor:default}#loco-editor .wg-split-x>nav.wg-tabs>a{display:inline-block;padding:.5em 1em;margin-top:.2em;color:#000;text-decoration:none;-webkit-border-radius:.2em .2em 0 0;-moz-border-radius:.2em .2em 0 0;-ms-border-radius:.2em .2em 0 0;-o-border-radius:.2em .2em 0 0;border-radius:.2em .2em 0 0;background-color:#f3f7fd}#loco-editor .wg-split-x>nav.wg-tabs>a:hover{background-color:#fff}#loco-editor .wg-split-x>nav.wg-tabs>a.active{background-color:#3db63d;color:#fff}#loco-editor .wg-split>div>.has-nav>.wg-body{margin-top:0px}#loco-editor .wg-dead{visibility:hidden}@media all and (max-width: 768px){#loco-editor .wg-split-x>div>.not-first>*{margin-left:20px}#loco-editor .wg-split-y>div>.not-first>*{margin-top:20px}#loco-editor .wg-split-x>div>.not-first:before{width:20px}#loco-editor .wg-split-y>div>.not-first:before{height:20px}#loco-editor .is-table .wg-thead header{padding-left:20px}}#loco-editor .is-table .po-fuzzy{color:#b59829;font-weight:bold}#loco-editor .is-table .po-empty{color:#1f507a;font-weight:bold}#loco-editor .is-table .po-flagged{color:#bd2c00}#loco-editor .is-table .wg-cols>div:first-child>div:before{font-family:loco;vertical-align:inherit;display:inline-block;content:" ";width:1.3em;line-height:1}#loco-editor .is-table .wg-cols>div:first-child>div.po-fuzzy:before{content:""}#loco-editor .is-table .wg-cols>div:first-child>div.po-flagged:before{content:""}#loco-editor .is-table .wg-cols>div:first-child>div.po-comment:before{content:"";color:#999}#loco-editor .is-table .wg-cols>div:first-child>div.po-unsaved:before{content:"";color:#f1d040}#loco-editor .is-table .wg-cols>div:first-child>div.selected:before{color:#fff !important}#loco-editor .wg-cell>.meta{color:#333;margin:0 !important;padding:6px 10px;font-weight:normal;font-size:13px;line-height:1.4em;cursor:default !important}#loco-editor .wg-cell>.meta>*{display:inline-block;margin-top:3px;margin-bottom:3px}#loco-editor .wg-cell>.meta>span{border:1px solid transparent;border-left:none}#loco-editor .wg-cell>.meta>mark{color:#fff;border-radius:2px;background-color:silver;border:1px solid silver;padding:0 .3em}#loco-editor .wg-cell>.meta>mark.tag{color:#999;background-color:#eee}#loco-editor .wg-cell>.meta>p{display:block;white-space:pre-line}#loco-editor .wg-cell>.meta .icon-warn{color:#c00}#loco-editor .wg-cell>.meta .has-icon:before{padding-right:0;width:17px}#loco-editor .wg-cell>.meta code{font-size:12px}#loco-editor .is-table .wg-cols>div>div>mark{display:inline-block;vertical-align:text-bottom;font:inherit;font-weight:normal;color:#fff;border-radius:2px;font-size:90%;line-height:1;padding:.2em .3em;background-color:rgba(0,0,0,.25)}#loco-editor .is-table .wg-cols>div>div.selected.po-flagged{background-color:#bd2c00}#loco-editor .is-table .wg-cols>div>div.selected.po-fuzzy{background-color:#b59829}#loco-editor .is-table .wg-cols>div>div.selected.po-empty{background-color:#999}#loco-editor #po-target header nav{display:block;position:absolute;right:0px;top:0px;padding:2px}#loco-editor #po-target header nav button{margin-left:5px}#loco-editor #po-target header nav.po-empty .icon-cloud{display:none !important}#loco-editor #po-list .wg-content{padding:0}#loco-editor #po-source>.wg-body>.has-title>header{background:transparent;font-weight:normal;float:left;clear:none;min-width:3.4em}#loco-editor #po-source>.wg-body>.has-title>.wg-content{clear:none}#loco-editor .has-title>header{line-height:normal;padding:6px}#loco-editor .has-title>header .lang{margin-right:6px;margin-bottom:1px}#loco-editor .trg-rtl #po-list-tbody .wg-cols>div[for=po-list-col-target]>div,#loco-editor .src-rtl #po-list-tbody .wg-cols>div[for=po-list-col-source]>div{direction:rtl;padding-left:0;padding-right:10px;text-align:right}#loco-editor #po-source>.wg-body>.has-title>h2{min-width:4.5em}#loco-editor .is-table .wg-td{font-size:13px}#loco-editor header,#loco-editor nav{display:block;position:relative}#loco-editor-inner{min-height:600px;font-size:14px;clear:both}#loco-editor-inner>div.loco-loading{height:100px;background:transparent url(../img/spin-editor-button.gif?v=2.4.4) center 20px no-repeat}#loco-editor-inner h2{color:#000;line-height:1}#loco-editor-inner .wg-cell>.meta code{padding:0;color:#0073aa;background:inherit;cursor:pointer}#loco-editor-inner .wg-cell>.meta code:hover{text-decoration:underline}#loco-admin.wrap #loco-editor>nav{font-size:14px;height:50px}#loco-admin.wrap #loco-editor>nav form{display:block;float:left;clear:none;padding:0;margin:0}#loco-admin.wrap #loco-editor>nav form.aux{float:right;margin-right:5px}#loco-admin.wrap #loco-editor>nav fieldset{display:block;position:relative;float:left;clear:none}#loco-admin.wrap #loco-editor>nav button,#loco-admin.wrap #loco-editor>nav input[type=text]{display:block;position:relative;float:left;clear:none;margin:5px 0 0 5px;height:36px;text-align:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#loco-admin.wrap #loco-editor>nav input[type=text]{padding:0 10px;font-size:14px;line-height:normal}#loco-admin.wrap #loco-editor>nav .invalid input[type=text]:focus{border-color:#c00;-webkit-box-shadow:0 0 2px rgba(153,0,0,.5);-moz-box-shadow:0 0 2px rgba(153,0,0,.5);box-shadow:0 0 2px rgba(153,0,0,.5)}#loco-admin.wrap #loco-editor>nav .loco-clearable{padding:0 20px}#loco-admin.wrap #loco-editor>nav .loco-clearable.invalid a.clear:before{color:#c00}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear{right:25px;line-height:2}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear:hover:before{color:#c00}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear:active:before{color:#000}#loco-admin.wrap #loco-editor>nav button.only-icon{width:40px}#loco-admin.wrap button.has-icon:before{width:16px;padding:0}#loco-admin.wrap button.has-icon.loco-loading:before{content:" ";height:16px;background:transparent url(../img/spin-editor-button.gif?v=2.4.4) 0 0 no-repeat}#loco-admin.wrap .button,#loco-admin.wrap .button-link,#loco-admin.wrap input[type=text]{border-color:#aaa;color:#444}#loco-admin.wrap .button:hover,#loco-admin.wrap .button-link:hover{color:#000}#loco-admin.wrap .button-primary,#loco-admin.wrap .button-primary:hover{color:#fff}#loco-admin.wrap button.icon-translate:before{font-size:16px}.loco-modal .loco-api{position:relative;padding:10px;background:#f7f7f7;border:solid 1px #eee;font-size:14px;margin-bottom:16px}.loco-modal .loco-api p{padding:0;margin:0;font-size:inherit}.loco-modal .loco-api blockquote{font-weight:bold;margin:0;padding:10px 0}.loco-modal .loco-api a.loco-api-credit{padding:0;display:block;position:absolute;right:10px;bottom:10px;text-decoration:none;white-space:nowrap;overflow:hidden;font-size:12px}.loco-modal .loco-api a.loco-api-credit:hover{text-decoration:underline}.loco-modal .loco-api-loading{text-indent:20px;background:transparent url(../img/spin-modal.gif?v=2.4.4) 10px center no-repeat}.loco-modal .loco-alert p{margin-bottom:2em;font-size:14px}.loco-modal .loco-alert nav{display:block;position:relative;margin:1em 0}.loco-modal .loco-alert nav a{display:inline-block;margin-right:1em;padding:10px}#loco-auto{display:none;min-width:50%;min-height:300px;position:relative}#loco-auto form blockquote{margin:0;padding:1em 0;font-size:14px}.loco-api a.loco-api-credit{color:inherit}.loco-api-yandex a.loco-api-credit:before{content:"Powered by "}.loco-api-google a.loco-api-credit{text-indent:200px;width:122px;height:16px;background:transparent url(../img/api/google.png?v=2.4.4) 0 0 no-repeat}.loco-api-microsoft a.loco-api-credit{text-indent:200px;width:152px;height:16px;background:transparent url(../img/api/microsoft.png?v=2.4.4) 0 0 no-repeat}.loco-api-deepl a.loco-api-credit{text-indent:200px;width:122px;height:16px;background:transparent url(../img/api/deepl.png?v=2.4.4) 0 0 no-repeat} #loco-editor{border:solid 1px #ccc}#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2.gif?v=2.4.5);background-repeat:no-repeat;min-height:16px}#loco-editor ._ajax_loader_f2x4{background:transparent url(../img/ajax-loader-f2-x4.gif?v=2.4.5) 0 0 no-repeat;min-height:75px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc.gif?v=2.4.5);background-repeat:no-repeat;min-height:16px}@media only screen and (-webkit-min-device-pixel-ratio: 2),only screen and (min--moz-device-pixel-ratio: 2),only screen and (-o-min-device-pixel-ratio: 2/1),only screen and (min-device-pixel-ratio: 2),only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx){#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2-x2.gif?v=2.4.5);background-size:16px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc-x2.gif?v=2.4.5);background-size:16px}}#loco-editor ._green_glow_inner,#loco-editor .is-editable>.wg-content>textarea:focus,#loco-editor .is-editable>.wg-content.has-focus .ace_scroller,#loco-editor .is-editable>.wg-content.has-focus .wysihtml-editor,#loco-editor .is-editable>.wg-content.has-focus .mce-content-body{-webkit-box-shadow:inset 0 0 10px 0 #3db63d;-moz-box-shadow:inset 0 0 10px 0 #3db63d;box-shadow:inset 0 0 10px 0 #3db63d}#loco-editor ._green_glow_outer{-webkit-box-shadow:0 0 .5em 0 #3db63d;-moz-box-shadow:0 0 .5em 0 #3db63d;box-shadow:0 0 .5em 0 #3db63d}#loco-editor .loco-font,#loco-editor .is-table .wg-thead .wg-sortable>header:after{font-family:"loco";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#loco-editor div.ta-mirror{position:absolute;top:0;border:solid 1px transparent;color:transparent;padding:.4em .6em;pointer-events:none}#loco-editor div.ta-mirror span{position:relative}#loco-editor div.ta-mirror span:after{color:#ccc;white-space:pre;display:inline-block;position:absolute;top:0;line-height:normal}#loco-editor div.ta-mirror .crlf:after{content:"¬"}#loco-editor div.ta-mirror .eof:after{content:"¶"}#loco-editor div.ta-mirror .x20:after{content:"·";color:#aaa}#loco-editor div.ta-mirror .x9:after{content:"⟶"}#loco-editor div.ta-mirror,#loco-editor .has-mirror textarea{white-space:pre-wrap;word-wrap:break-word;word-spacing:0px}#loco-editor .has-mirror ::placeholder{color:transparent}#loco-editor .has-mirror ::-webkit-input-placeholder{color:transparent}#loco-editor .has-mirror :-moz-placeholder{color:transparent;opacity:1}#loco-editor .has-mirror ::-moz-placeholder{color:transparent;opacity:1}#loco-editor .has-mirror :-ms-input-placeholder{color:transparent}#loco-editor .has-mirror .ielt10 .placeheld{color:transparent}#loco-editor div.ta-mirror{left:0;text-align:left}#loco-editor div.ta-mirror span:after{left:0}#loco-editor div.ta-mirror .eol:after{padding-left:.2em}#loco-editor [dir=RTL] div.ta-mirror{left:auto;right:0;text-align:right}#loco-editor [dir=RTL] div.ta-mirror span:after{right:0}#loco-editor [dir=RTL] div.ta-mirror .eol:after{padding-left:0;padding-right:.2em}#loco-editor .has-proxy>textarea{display:none !important}#loco-editor .has-proxy .ace_editor{height:100%;font-size:13px !important;line-height:1.4 !important}#loco-editor .has-proxy .ace_editor .ace_marker-layer .ace_bracket{display:none}#loco-editor .has-proxy .ace_print-margin{display:none}#loco-editor .ace_printf{color:#b90690;background-color:#edf1be}#loco-editor .ace_locked{color:gray}#loco-editor .ace_icu-quoted{color:gray}#loco-editor .ace_icu{color:#697eb9}#loco-editor .ace_icu.ace_name{color:#b90600}#loco-editor .resizer{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0 0 6px 0;background:#f0f0f0 url(../img/wg/splity.png?v=2.4.5) center bottom no-repeat;border:1px solid #ddd;overflow:hidden;cursor:move;cursor:row-resize;cursor:s-resize}#loco-editor .resizer>*{height:100%;border:none}#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2.gif?v=2.4.5);background-repeat:no-repeat;min-height:16px}#loco-editor ._ajax_loader_f2x4{background:transparent url(../img/ajax-loader-f2-x4.gif?v=2.4.5) 0 0 no-repeat;min-height:75px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc.gif?v=2.4.5);background-repeat:no-repeat;min-height:16px}@media only screen and (-webkit-min-device-pixel-ratio: 2),only screen and (min--moz-device-pixel-ratio: 2),only screen and (-o-min-device-pixel-ratio: 2/1),only screen and (min-device-pixel-ratio: 2),only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx){#loco-editor ._ajax_loader_f2{background-image:url(../img/ajax-loader-f2-x2.gif?v=2.4.5);background-size:16px}#loco-editor ._ajax_loader_cc{background-image:url(../img/ajax-loader-cc-x2.gif?v=2.4.5);background-size:16px}}#loco-editor ._green_glow_inner,#loco-editor .is-editable>.wg-content>textarea:focus,#loco-editor .is-editable>.wg-content.has-focus .ace_scroller,#loco-editor .is-editable>.wg-content.has-focus .wysihtml-editor,#loco-editor .is-editable>.wg-content.has-focus .mce-content-body{-webkit-box-shadow:inset 0 0 10px 0 #3db63d;-moz-box-shadow:inset 0 0 10px 0 #3db63d;box-shadow:inset 0 0 10px 0 #3db63d}#loco-editor ._green_glow_outer{-webkit-box-shadow:0 0 .5em 0 #3db63d;-moz-box-shadow:0 0 .5em 0 #3db63d;box-shadow:0 0 .5em 0 #3db63d}#loco-editor .loco-font,#loco-editor .is-table .wg-thead .wg-sortable>header:after{font-family:"loco";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#loco-editor .wg-cell,#loco-editor .wg-cell>div{clear:both;position:relative;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;outline:none}#loco-editor .wg-cell{left:0;top:0;padding:0;margin:0;overflow:hidden}#loco-editor .wg-split{background:#eee}#loco-editor .wg-body:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0}#loco-editor .wg-split-x>div>.not-first>*{margin-left:6px}#loco-editor .wg-split-y>div>.not-first>*{margin-top:6px}#loco-editor .wg-split>div>.has-title .wg-content{margin-top:0}#loco-editor .wg-split-x>div>.wg-cell{float:left;clear:none;height:100%}#loco-editor .wg-split-x>div{cursor:move;cursor:ew-resize;cursor:col-resize}#loco-editor .wg-split>div>.not-first:before{display:block;position:absolute;overflow:hidden;content:" "}#loco-editor .wg-split-x>div>.not-first:before{width:6px;height:100%;background:transparent url(../img/wg/splitx.png?v=2.4.5) center center no-repeat}#loco-editor .wg-split-y>div{cursor:move;cursor:ns-resize;cursor:row-resize}#loco-editor .wg-split-y>div>.not-first:before{height:6px;width:100%;background:transparent url(../img/wg/splity.png?v=2.4.5) center center no-repeat}#loco-editor .wg-split>div.locked{cursor:default}#loco-editor .wg-split-x>div.locked>.not-first>*{margin-left:0px}#loco-editor .wg-split-y>div.locked>.not-first>*{margin-top:0px}#loco-editor .wg-split>div.locked>.not-first:before{display:none}#loco-editor .has-title>header{background:#e2e2e2;cursor:default !important;margin:0;white-space:nowrap}#loco-editor .wg-content{background:#fff;cursor:default;padding:4px 6px;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#loco-editor .wg-toolbar{top:0;right:0;margin-top:6px;position:absolute}#loco-editor .wg-toolbar>span{color:#fff;background:#000;display:block;padding:0 6px;cursor:default !important}#loco-editor .wg-toolbar>span:active{color:#000;background-color:#fff}#loco-editor .wg-content,#loco-editor .wg-tbody>div{overflow:scroll;overflow-x:hidden;overflow-y:auto}#loco-editor .is-table{background-color:#fff}#loco-editor .is-table .wg-thead .has-title>header{font-weight:normal;background:transparent;padding:4px 0;margin:0 0 0 10px}#loco-editor .is-table .wg-thead>div>.not-first:before{background-position:center center}#loco-editor .is-table .wg-thead{background:#e2e2e2;border-bottom:solid 1px #ccc}#loco-editor .is-table .wg-tbody{background-image:url(data:image/gif;base64,R0lGODlhAQAsAIABAPz8/P///yH5BAEAAAEALAAAAAABACwAAAIIjI+pAe0PIygAOw==);position:relative}#loco-editor .is-table .wg-cols>div{float:left;clear:none}#loco-editor .is-table .wg-cols>div>div{white-space:nowrap;line-height:1.7em;padding-left:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis;-ms-text-overflow:ellipsis;background-color:#fff}#loco-editor .is-table .wg-cols>div>div:nth-child(even){background-color:#f7f7f7}#loco-editor .is-table .wg-cols>div>div.selected{background-color:#3db63d;color:#fff}#loco-editor .is-table .wg-cols>div>div.selected::selection{background-color:#fff;color:#000}#loco-editor .is-table .wg-cols>div:first-child>div{padding-left:4px}#loco-editor .is-table .wg-dead{clear:both}#loco-editor .is-table .wg-thead .wg-sortable>header{cursor:pointer !important}#loco-editor .is-table .wg-thead .wg-sortable>header:after{padding:0 0 0 5px;color:#999}#loco-editor .is-table .wg-thead .wg-sortable.wg-asc>header:after{content:"▲"}#loco-editor .is-table .wg-thead .wg-sortable.wg-desc>header:after{content:"▼"}#loco-editor .is-table .wg-thead .wg-sortable:hover>header:after{color:#000}#loco-editor .is-field>.wg-content{cursor:text;padding:0;line-height:normal;overflow:hidden;overflow-y:hidden}#loco-editor .is-field>.wg-content>div,#loco-editor .is-field>.wg-content>textarea{font-size:14px;line-height:1.4;border:1px solid #ddd;width:100%;height:100%;padding:8px 10px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:0;-moz-border-radius:0;-ms-border-radius:0;-o-border-radius:0;border-radius:0}#loco-editor .is-field>.wg-content textarea{resize:none;overflow:auto;display:block}#loco-editor .is-field>.wg-content>.ace_editor{padding:0;border-width:0}#loco-editor .is-field>.wg-content>div[contenteditable]{overflow:scroll;overflow-x:hidden;overflow-y:auto}#loco-editor .is-readonly>.wg-content{cursor:default}#loco-editor .is-readonly>.wg-content>div,#loco-editor .is-readonly>.wg-content>textarea,#loco-editor .is-readonly>.wg-content>textarea[readonly]{background:#f8f8f8;text-shadow:0 1px #fff;color:inherit}#loco-editor .is-readonly>.wg-content .ace_scroller{cursor:default;background:#f8f8f8}#loco-editor .is-readonly>.wg-content .ace_cursor-layer{display:none}#loco-editor .is-readonly>.wg-content>textarea[readonly]{cursor:default}#loco-editor .is-editable>.wg-content[dir=RTL] .ace_editor .ace_line{direction:ltr;unicode-bidi:bidi-override}#loco-editor .wg-split-x>nav.wg-tabs{white-space:nowrap;text-align:center;cursor:default}#loco-editor .wg-split-x>nav.wg-tabs>a{display:inline-block;padding:.5em 1em;margin-top:.2em;color:#000;text-decoration:none;-webkit-border-radius:.2em .2em 0 0;-moz-border-radius:.2em .2em 0 0;-ms-border-radius:.2em .2em 0 0;-o-border-radius:.2em .2em 0 0;border-radius:.2em .2em 0 0;background-color:#f3f7fd}#loco-editor .wg-split-x>nav.wg-tabs>a:hover{background-color:#fff}#loco-editor .wg-split-x>nav.wg-tabs>a.active{background-color:#3db63d;color:#fff}#loco-editor .wg-split>div>.has-nav>.wg-body{margin-top:0px}#loco-editor .wg-dead{visibility:hidden}@media all and (max-width: 768px){#loco-editor .wg-split-x>div>.not-first>*{margin-left:20px}#loco-editor .wg-split-y>div>.not-first>*{margin-top:20px}#loco-editor .wg-split-x>div>.not-first:before{width:20px}#loco-editor .wg-split-y>div>.not-first:before{height:20px}#loco-editor .is-table .wg-thead header{padding-left:20px}}#loco-editor .is-table .po-fuzzy{color:#b59829;font-weight:bold}#loco-editor .is-table .po-empty{color:#1f507a;font-weight:bold}#loco-editor .is-table .po-flagged{color:#bd2c00}#loco-editor .is-table .wg-cols>div:first-child>div:before{font-family:loco;vertical-align:inherit;display:inline-block;content:" ";width:1.3em;line-height:1}#loco-editor .is-table .wg-cols>div:first-child>div.po-fuzzy:before{content:""}#loco-editor .is-table .wg-cols>div:first-child>div.po-flagged:before{content:""}#loco-editor .is-table .wg-cols>div:first-child>div.po-comment:before{content:"";color:#999}#loco-editor .is-table .wg-cols>div:first-child>div.po-unsaved:before{content:"";color:#f1d040}#loco-editor .is-table .wg-cols>div:first-child>div.selected:before{color:#fff !important}#loco-editor .wg-cell>.meta{color:#333;margin:0 !important;padding:6px 10px;font-weight:normal;font-size:13px;line-height:1.4em;cursor:default !important}#loco-editor .wg-cell>.meta>*{display:inline-block;margin-top:3px;margin-bottom:3px}#loco-editor .wg-cell>.meta>span{border:1px solid transparent;border-left:none}#loco-editor .wg-cell>.meta>mark{color:#fff;border-radius:2px;background-color:silver;border:1px solid silver;padding:0 .3em}#loco-editor .wg-cell>.meta>mark.tag{color:#999;background-color:#eee}#loco-editor .wg-cell>.meta>p{display:block;white-space:pre-line}#loco-editor .wg-cell>.meta .icon-warn{color:#c00}#loco-editor .wg-cell>.meta .has-icon:before{padding-right:0;width:17px}#loco-editor .wg-cell>.meta code{font-size:12px}#loco-editor .is-table .wg-cols>div>div>mark{display:inline-block;vertical-align:text-bottom;font:inherit;font-weight:normal;color:#fff;border-radius:2px;font-size:90%;line-height:1;padding:.2em .3em;background-color:rgba(0,0,0,.25)}#loco-editor .is-table .wg-cols>div>div.selected.po-flagged{background-color:#bd2c00}#loco-editor .is-table .wg-cols>div>div.selected.po-fuzzy{background-color:#b59829}#loco-editor .is-table .wg-cols>div>div.selected.po-empty{background-color:#999}#loco-editor #po-target header nav{display:block;position:absolute;right:0px;top:0px;padding:2px}#loco-editor #po-target header nav button{margin-left:5px}#loco-editor #po-target header nav.po-empty .icon-cloud{display:none !important}#loco-editor #po-list .wg-content{padding:0}#loco-editor #po-source>.wg-body>.has-title>header{background:transparent;font-weight:normal;float:left;clear:none;min-width:3.4em}#loco-editor #po-source>.wg-body>.has-title>.wg-content{clear:none}#loco-editor .has-title>header{line-height:normal;padding:6px}#loco-editor .has-title>header .lang{margin-right:6px;margin-bottom:1px}#loco-editor .trg-rtl #po-list-tbody .wg-cols>div[for=po-list-col-target]>div,#loco-editor .src-rtl #po-list-tbody .wg-cols>div[for=po-list-col-source]>div{direction:rtl;padding-left:0;padding-right:10px;text-align:right}#loco-editor #po-source>.wg-body>.has-title>h2{min-width:4.5em}#loco-editor .is-table .wg-td{font-size:13px}#loco-editor header,#loco-editor nav{display:block;position:relative}#loco-editor-inner{min-height:600px;font-size:14px;clear:both}#loco-editor-inner>div.loco-loading{height:100px;background:transparent url(../img/spin-editor-button.gif?v=2.4.5) center 20px no-repeat}#loco-editor-inner h2{color:#000;line-height:1}#loco-editor-inner .wg-cell>.meta code{padding:0;color:#0073aa;background:inherit;cursor:pointer}#loco-editor-inner .wg-cell>.meta code:hover{text-decoration:underline}#loco-admin.wrap #loco-editor>nav{font-size:14px;height:50px}#loco-admin.wrap #loco-editor>nav form{display:block;float:left;clear:none;padding:0;margin:0}#loco-admin.wrap #loco-editor>nav form.aux{float:right;margin-right:5px}#loco-admin.wrap #loco-editor>nav fieldset{display:block;position:relative;float:left;clear:none}#loco-admin.wrap #loco-editor>nav button,#loco-admin.wrap #loco-editor>nav input[type=text]{display:block;position:relative;float:left;clear:none;margin:5px 0 0 5px;height:36px;text-align:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#loco-admin.wrap #loco-editor>nav input[type=text]{padding:0 10px;font-size:14px;line-height:normal}#loco-admin.wrap #loco-editor>nav .invalid input[type=text]:focus{border-color:#c00;-webkit-box-shadow:0 0 2px rgba(153,0,0,.5);-moz-box-shadow:0 0 2px rgba(153,0,0,.5);box-shadow:0 0 2px rgba(153,0,0,.5)}#loco-admin.wrap #loco-editor>nav .loco-clearable{padding:0 20px}#loco-admin.wrap #loco-editor>nav .loco-clearable.invalid a.clear:before{color:#c00}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear{right:25px;line-height:2}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear:hover:before{color:#c00}#loco-admin.wrap #loco-editor>nav .loco-clearable a.clear:active:before{color:#000}#loco-admin.wrap #loco-editor>nav button.only-icon{width:40px}#loco-admin.wrap button.has-icon:before{width:16px;padding:0}#loco-admin.wrap button.has-icon.loco-loading:before{content:" ";height:16px;background:transparent url(../img/spin-editor-button.gif?v=2.4.5) 0 0 no-repeat}#loco-admin.wrap .button,#loco-admin.wrap .button-link,#loco-admin.wrap input[type=text]{border-color:#aaa;color:#444}#loco-admin.wrap .button:hover,#loco-admin.wrap .button-link:hover{color:#000}#loco-admin.wrap .button-primary,#loco-admin.wrap .button-primary:hover{color:#fff}#loco-admin.wrap button.icon-translate:before{font-size:16px}.loco-modal .loco-api{position:relative;padding:10px;background:#f7f7f7;border:solid 1px #eee;font-size:14px;margin-bottom:16px}.loco-modal .loco-api p{padding:0;margin:0;font-size:inherit}.loco-modal .loco-api blockquote{font-weight:bold;margin:0;padding:10px 0}.loco-modal .loco-api a.loco-api-credit{padding:0;display:block;position:absolute;right:10px;bottom:10px;text-decoration:none;white-space:nowrap;overflow:hidden;font-size:12px}.loco-modal .loco-api a.loco-api-credit:hover{text-decoration:underline}.loco-modal .loco-api-loading{text-indent:20px;background:transparent url(../img/spin-modal.gif?v=2.4.5) 10px center no-repeat}.loco-modal .loco-alert p{margin-bottom:2em;font-size:14px}.loco-modal .loco-alert nav{display:block;position:relative;margin:1em 0}.loco-modal .loco-alert nav a{display:inline-block;margin-right:1em;padding:10px}#loco-auto{display:none;min-width:50%;min-height:300px;position:relative}#loco-auto form blockquote{margin:0;padding:1em 0;font-size:14px}.loco-api a.loco-api-credit{color:inherit}.loco-api-yandex a.loco-api-credit:before{content:"Powered by "}.loco-api-google a.loco-api-credit{text-indent:200px;width:122px;height:16px;background:transparent url(../img/api/google.png?v=2.4.5) 0 0 no-repeat}.loco-api-microsoft a.loco-api-credit{text-indent:200px;width:152px;height:16px;background:transparent url(../img/api/microsoft.png?v=2.4.5) 0 0 no-repeat}.loco-api-deepl a.loco-api-credit{text-indent:200px;width:122px;height:16px;background:transparent url(../img/api/deepl.png?v=2.4.5) 0 0 no-repeat}
\ No newline at end of file \ No newline at end of file
#loco-admin.wrap .revisions-diff{padding:10px;min-height:20px}#loco-admin.wrap table.diff{border-collapse:collapse}#loco-admin.wrap table.diff td{white-space:nowrap;overflow:hidden;font:normal 12px/17px "Monaco","Menlo","Ubuntu Mono","Consolas","source-code-pro",monospace;padding:2px}#loco-admin.wrap table.diff td>span{color:#aaa}#loco-admin.wrap table.diff td>span:after{content:". "}#loco-admin.wrap table.diff tbody{border-top:1px dashed #ccc}#loco-admin.wrap table.diff tbody:first-child{border-top:none}#loco-admin.wrap .revisions.loading .diff-meta{color:#eee}#loco-admin.wrap .revisions.loading .loading-indicator span.spinner{visibility:visible;background:#fff url(../img/spin-modal.gif?v=2.4.4) center center no-repeat}#loco-admin.wrap .revisions-meta{clear:both;padding:10px 12px;margin:0;position:relative;top:10px}#loco-admin.wrap .revisions-meta .diff-meta{clear:none;float:left;width:50%;padding:0;min-height:auto}#loco-admin.wrap .revisions-meta .diff-meta button{margin-top:5px}#loco-admin.wrap .revisions-meta .diff-meta-current{float:right;text-align:right}#loco-admin.wrap .revisions-meta time{color:#72777c}#loco-admin.wrap .revisions-control-frame{margin:10px 0}#loco-admin.wrap .revisions-diff-frame{margin-top:20px} #loco-admin.wrap .revisions-diff{padding:10px;min-height:20px}#loco-admin.wrap table.diff{border-collapse:collapse}#loco-admin.wrap table.diff td{white-space:nowrap;overflow:hidden;font:normal 12px/17px "Monaco","Menlo","Ubuntu Mono","Consolas","source-code-pro",monospace;padding:2px}#loco-admin.wrap table.diff td>span{color:#aaa}#loco-admin.wrap table.diff td>span:after{content:". "}#loco-admin.wrap table.diff tbody{border-top:1px dashed #ccc}#loco-admin.wrap table.diff tbody:first-child{border-top:none}#loco-admin.wrap .revisions.loading .diff-meta{color:#eee}#loco-admin.wrap .revisions.loading .loading-indicator span.spinner{visibility:visible;background:#fff url(../img/spin-modal.gif?v=2.4.5) center center no-repeat}#loco-admin.wrap .revisions-meta{clear:both;padding:10px 12px;margin:0;position:relative;top:10px}#loco-admin.wrap .revisions-meta .diff-meta{clear:none;float:left;width:50%;padding:0;min-height:auto}#loco-admin.wrap .revisions-meta .diff-meta button{margin-top:5px}#loco-admin.wrap .revisions-meta .diff-meta-current{float:right;text-align:right}#loco-admin.wrap .revisions-meta time{color:#72777c}#loco-admin.wrap .revisions-control-frame{margin:10px 0}#loco-admin.wrap .revisions-diff-frame{margin-top:20px}
\ No newline at end of file \ No newline at end of file
.js #loco-admin.wrap .loco-loading{min-height:100px;background:#fff url(../img/spin-modal.gif?v=2.4.4) center center no-repeat}.js #loco-admin.wrap .loco-loading ol.msgcat{display:none}#loco-admin.wrap #loco-po{padding-right:0;overflow:auto}#loco-admin.wrap ol.msgcat{margin-left:3em;padding-top:1em;border-top:1px dashed #ccc}#loco-admin.wrap ol.msgcat:first-child{padding-top:0;border-top:none}#loco-admin.wrap ol.msgcat li{color:#aaa;margin:0;padding:0 0 0 1em;font:normal 12px/17px "Monaco","Menlo","Ubuntu Mono","Consolas","source-code-pro",monospace;border-left:1px solid #eee}#loco-admin.wrap ol.msgcat li>*{color:#333;white-space:pre}#loco-admin.wrap ol.msgcat li>.po-comment{color:#3cc200}#loco-admin.wrap ol.msgcat li>.po-refs{color:#0073aa}#loco-admin.wrap ol.msgcat li>.po-refs a{color:inherit;text-decoration:none}#loco-admin.wrap ol.msgcat li>.po-refs a:hover{text-decoration:underline}#loco-admin.wrap ol.msgcat li>.po-flags{color:#77904a}#loco-admin.wrap ol.msgcat li>.po-flags em{font-style:normal}#loco-admin.wrap ol.msgcat li>.po-word{color:#000}#loco-admin.wrap ol.msgcat li>.po-junk{font-style:italic;color:#ccc}#loco-admin.wrap ol.msgcat li>.po-string>span{color:#c931c7}#loco-admin.wrap form.loco-filter{top:0;right:0;position:absolute}#loco-admin.wrap .loco-invalid form.loco-filter input[type=text]:focus{border-color:#c00;-webkit-box-shadow:0 0 2px rgba(153,0,0,.5);-moz-box-shadow:0 0 2px rgba(153,0,0,.5);box-shadow:0 0 2px rgba(153,0,0,.5)}#loco-admin.wrap .loco-invalid ol.msgcat{list-style-type:none}#loco-admin.wrap .loco-invalid ol.msgcat li{color:#000} .js #loco-admin.wrap .loco-loading{min-height:100px;background:#fff url(../img/spin-modal.gif?v=2.4.5) center center no-repeat}.js #loco-admin.wrap .loco-loading ol.msgcat{display:none}#loco-admin.wrap #loco-po{padding-right:0;overflow:auto}#loco-admin.wrap ol.msgcat{margin-left:3em;padding-top:1em;border-top:1px dashed #ccc}#loco-admin.wrap ol.msgcat:first-child{padding-top:0;border-top:none}#loco-admin.wrap ol.msgcat li{color:#aaa;margin:0;padding:0 0 0 1em;font:normal 12px/17px "Monaco","Menlo","Ubuntu Mono","Consolas","source-code-pro",monospace;border-left:1px solid #eee}#loco-admin.wrap ol.msgcat li>*{color:#333;white-space:pre}#loco-admin.wrap ol.msgcat li>.po-comment{color:#3cc200}#loco-admin.wrap ol.msgcat li>.po-refs{color:#0073aa}#loco-admin.wrap ol.msgcat li>.po-refs a{color:inherit;text-decoration:none}#loco-admin.wrap ol.msgcat li>.po-refs a:hover{text-decoration:underline}#loco-admin.wrap ol.msgcat li>.po-flags{color:#77904a}#loco-admin.wrap ol.msgcat li>.po-flags em{font-style:normal}#loco-admin.wrap ol.msgcat li>.po-word{color:#000}#loco-admin.wrap ol.msgcat li>.po-junk{font-style:italic;color:#ccc}#loco-admin.wrap ol.msgcat li>.po-string>span{color:#c931c7}#loco-admin.wrap form.loco-filter{top:0;right:0;position:absolute}#loco-admin.wrap .loco-invalid form.loco-filter input[type=text]:focus{border-color:#c00;-webkit-box-shadow:0 0 2px rgba(153,0,0,.5);-moz-box-shadow:0 0 2px rgba(153,0,0,.5);box-shadow:0 0 2px rgba(153,0,0,.5)}#loco-admin.wrap .loco-invalid ol.msgcat{list-style-type:none}#loco-admin.wrap .loco-invalid ol.msgcat li{color:#000}
\ No newline at end of file \ No newline at end of file
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(9,100,132,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#096484;foo:#096484}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1cdc7 !important;background:#db9925 !important;border-color:#db9925 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/blue/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(9,100,132,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#096484;foo:#096484}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1cdc7 !important;background:#db9925 !important;border-color:#db9925 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/blue/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(199,165,137,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#c7a589;foo:#c7a589}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1ccc7 !important;background:#ba906d !important;border-color:#ba906d !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/coffee/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(199,165,137,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#c7a589;foo:#c7a589}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1ccc7 !important;background:#ba906d !important;border-color:#ba906d !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/coffee/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(163,183,69,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#a3b745;foo:#a3b745}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#cfd1c7 !important;background:#89993a !important;border-color:#89993a !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/ectoplasm/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(163,183,69,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#a3b745;foo:#a3b745}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#cfd1c7 !important;background:#89993a !important;border-color:#89993a !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/ectoplasm/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(136,136,136,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#888;foo:#04a4cc}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#c7cfd1 !important;background:#0384a4 !important;border-color:#0384a4 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/light/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(136,136,136,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#888;foo:#04a4cc}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#c7cfd1 !important;background:#0384a4 !important;border-color:#0384a4 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/light/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(225,77,67,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#e14d43;foo:#e14d43}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1c8c7 !important;background:#d92e23 !important;border-color:#d92e23 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/midnight/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(225,77,67,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#e14d43;foo:#e14d43}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1c8c7 !important;background:#d92e23 !important;border-color:#d92e23 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/midnight/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(56,88,233,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#3858e9;foo:#3858e9}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#c7c9d1 !important;background:#193ddf !important;border-color:#193ddf !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/modern/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(56,88,233,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#3858e9;foo:#3858e9}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#c7c9d1 !important;background:#193ddf !important;border-color:#193ddf !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/modern/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(158,186,160,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#9ebaa0;foo:#9ebaa0}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#c7d1c8 !important;background:#86a989 !important;border-color:#86a989 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/ocean/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(158,186,160,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#9ebaa0;foo:#9ebaa0}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#c7d1c8 !important;background:#86a989 !important;border-color:#86a989 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/ocean/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(221,130,59,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#dd823b;foo:#dd823b}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1cbc7 !important;background:#cc6d23 !important;border-color:#cc6d23 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/sunrise/spin-primary-button.gif?v=2.4.4) 0 0 no-repeat !important} .wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(221,130,59,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#dd823b;foo:#dd823b}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}.wp-core-ui .button-primary.loco-loading[disabled]{color:#d1cbc7 !important;background:#cc6d23 !important;border-color:#cc6d23 !important}.wp-core-ui .button-primary.loco-loading[disabled]:before{background:transparent url(../../img/skins/sunrise/spin-primary-button.gif?v=2.4.5) 0 0 no-repeat !important}
This source diff could not be displayed because it is too large. You can view the blob instead.
!function(S,C){var _=S.loco,i=_&&_.conf,p=document.getElementById("loco-editor-inner");if(_&&i&&p){var D,r,t,z,h,l,f=!!i.WP_DEBUG,s=_.po.ref&&_.po.ref.init(_,i),c=null,a=null,o=i.multipart,T=_.l10n,b=_.string.sprintf,I=i.locale,y=_.po.init(I).wrap(i.powrap),u=!I,n=document.getElementById("loco-actions"),d=i.popath,g=i.potpath,e=document.getElementById("loco-fs"),v=e&&_.fs.init(e),m=i.readonly,w=!m,j={},x=0,k={my:"top",at:"top",of:"#loco-content"};!o||S.FormData&&S.Blob||(o=!1,_.notices.warn("Your browser doesn't support Ajax file uploads. Falling back to standard postdata")),s||_.notices.warn("admin.js is out of date. Please empty your browser cache and reload the page.");var M,L,E=(L=parseInt(C(p).css("min-height")||0),function(){var t=function(t,n){for(var o=t.offsetTop||0;(t=t.offsetParent)&&t!==n;)o+=t.offsetTop||0;return o}(p,document.body),n=S.innerHeight,o=Math.max(L,n-t-20);M!==o&&(p.style.height=String(o)+"px",M=o)});E(),C(S).resize(E),p.innerHTML="",D=_.po.ed.init(p).localise(T),_.po.kbd.init(D).add("save",w?function(){D.dirty&&R()}:W).add("hint",I&&w&&A||W).enable("copy","clear","enter","next","prev","fuzzy","save","invis","hint");var U={save:w&&function(n){function o(){n.disabled=!0}function t(){n.disabled=!1}function e(){t(),C(n).removeClass("loco-loading")}return n,D.on("poUnsaved",function(){t(),C(n).addClass("button-primary")}).on("poSave",function(){o(),C(n).removeClass("button-primary")}),a=C.extend({path:d},i.project||{}),C(n).click(function(t){return t.preventDefault(),o(),C(n).addClass("loco-loading"),R(e),!1}),!0},sync:w&&function(n){var t=i.project;if(t){function o(){n.disabled=!0}function e(){n.disabled=!1}function a(){e(),C(n).removeClass("loco-loading")}D.on("poUnsaved",function(){o()}).on("poSave",function(){e()}),c={bundle:t.bundle,domain:t.domain,type:u?"pot":"po",sync:g||"",strip:"pot"===String(i.syncmode).toLowerCase()?"1":""},C(n).click(function(t){return t.preventDefault(),o(),C(n).addClass("loco-loading"),P(a),!1}),e()}return!0},revert:function(t){return D.on("poUnsaved",function(){t.disabled=!1}).on("poSave",function(){t.disabled=!0}),C(t).click(function(t){return t.preventDefault(),location.reload(),!1}),!0},invs:function(t){var o=C(t);return t.disabled=!1,D.on("poInvs",function(t,n){o[n?"addClass":"removeClass"]("inverted")}),o.click(function(t){return t.preventDefault(),D.setInvs(!D.getInvs()),!1}),_.tooltip.init(o),!0},code:function(t){var o=C(t);return t.disabled=!1,o.click(function(t){t.preventDefault();var n=!D.getMono();return o[n?"addClass":"removeClass"]("inverted"),D.setMono(n),!1}),_.tooltip.init(o),!0},source:$,binary:u?null:$};u?(U.add=w&&function(t){return t.disabled=!1,C(t).click(function(t){t.preventDefault();var n,o=1,e=/(\d+)$/;for(n="New message";y.get(n);)o=e.exec(n)?Math.max(o,RegExp.$1):o,n="New message "+ ++o;return D.add(n),!1}),!0},U.del=w&&function(t){return t.disabled=!1,C(t).click(function(t){return t.preventDefault(),D.del(),!1}),!0}):U.auto=function(t){function n(){t.disabled=!1}return D.on("poUnsaved",function(){t.disabled=!0}).on("poSave poAuto",function(){n()}),C(t).click(F),n(),!0},C("#loco-editor > nav .button").each(function(t,n){var o=n.getAttribute("data-loco"),e=U[o];e&&e(n,o)||C(n).addClass("loco-noop")}),C(n).submit(W),function(n){function e(t){C(n.parentNode)[t||null==t?"removeClass":"addClass"]("invalid")}D.searchable(_.fulltext.init()),n.disabled=!1,n.value="";var a=_.watchtext(n,function(t){e(D.filter(t,!0))});D.on("poFilter",function(t,n,o){a.val(n||""),e(o)}).on("poMerge",function(t,n){var o=a.val();o&&D.filter(o)})}(document.getElementById("loco-search")),D.on("poUnsaved",function(){S.onbeforeunload=H}).on("poSave",function(){Y(),S.onbeforeunload=null}).on("poHint",A).on("poUpdate",Y).on("poMeta",function(t,n){var o,e,a=(e="CODE",(o=n).tagName===e?o:o.getElementsByTagName(e)[0]);return!a||!s||(s.load(a.textContent),t.preventDefault(),!1)}),y.load(i.podata),D.load(y),(I=D.targetLocale)?I.isRTL()&&C(p).addClass("trg-rtl"):D.unlock(),Y(),delete _.conf,i=U=null}function P(d){_.ajax.post("sync",c,function(t){var n=[],o=y,e=t.po,a=t.pot,i=_.po.init().load(e),r=o.merge(i),l=r.add.length,s=r.del.length,c=r.fuz.length,u=T;D.load(o),l||s||c?(a?n.push(b(u._("Merged from %s"),a)):n.push(u._("Merged from source code")),l&&n.push(b(u._n("1 new string added","%s new strings added",l),l)),s&&n.push(b(u._n("1 obsolete string removed","%s obsolete strings removed",s),s)),c&&n.push(b(u._n("1 string marked Fuzzy","%s strings marked Fuzzy",c),c)),C(p).trigger("poUnsaved",[]),Y(),f&&S.console&&function(t,n){function o(t){var n=t.source(),o=t.context();return o?"["+o+"] "+n:n}var e=-1,a=n.add.length;for(;++e<a;)t.log(" + "+o(n.add[e]));for(a=n.del.length,e=0;e<a;e++)t.log(" - "+o(n.del[e]));for(a=n.fuz.length,e=0;e<a;e++)t.log(" ~ "+o(n.fuz[e]))}(console,r)):a?n.push(b(u._("Strings up to date with %s"),a)):n.push(u._("Strings up to date with source code")),_.notices.success(n.join(". ")),C(p).trigger("poMerge",[t]),d&&d()},d)}function q(){return t=t||function(){for(var t,n=-1,o=[],e=r,a=e.length;++n<a;)try{t=e[n],o.push(_.apis.create(t))}catch(t){_.notices.error(String(t))}return o}()}function B(e){var a;function i(){return(new Date).getTime()}u||m?_.notices.error("Logic error. APIs not available in current mode"):null==r||0===r.length||10<Math.round((i()-x)/1e3)?(l&&l.remove(),l=null,h&&h.remove(),h=null,z&&z.remove(),r=z=null,a=C('<div><div class="loco-loading"></div></div>').dialog({dialogClass:"loco-modal loco-modal-no-close",appendTo:"#loco-admin.wrap",title:"Loading..",modal:!0,autoOpen:!0,closeOnEscape:!1,resizable:!1,draggable:!1,position:k,height:200}),_.ajax.get("apis",{locale:String(I)},function(t,n,o){x=i(),0===(r=t&&t.apis||[]).length?l=O("loco-apis-empty",t.html):h=O("loco-apis-batch",t.html),a.remove(),e(r)})):(x=i(),e(r))}function O(t,n){var o=C(n);return o.attr("id",t),o.dialog({dialogClass:"loco-modal",appendTo:"#loco-admin.wrap",title:o.attr("title"),modal:!0,autoOpen:!1,closeOnEscape:!0,resizable:!1,draggable:!1,position:k}),o}function A(){B(function(t){t.length?function(){var p=T,t=D.current(),n=D.getTargetOffset(),o=t&&t.source(null,n),f='lang="'+String(I)+'" dir="'+(I.isRTL()?"RTL":"LTR")+'"',g=99;if(!o)return;function e(t){return!t.isDefaultPrevented()&&(!(0<=(n=t.which-49)&&n<10&&(o=m&&m.find("button.button-primary").eq(n))&&1===o.length)||(t.preventDefault(),t.stopPropagation(),o.click(),!1));var n,o}function a(t,n,o,e){var a=e.getId(),i=x[a],r=String(i+1),l=e.getUrl(),s=p._("Use this translation"),c=String(e),u=y&&y[a],d=C('<button class="button button-primary"></button>').attr("tabindex",String(1+g+i)).on("click",function(e,a){return function(t){t.preventDefault(),t.stopPropagation(),v();var n=D.current(),o=D.getTargetOffset();n&&n.source(null,o)===e?(n.translate(a,o),D.focus().reloadMessage(n)):_.notices.warn("Source changed since suggestion")}}(t,n));d.attr("accesskey",r),1<h.length&&(s+=" ("+r+")"),d.text(s),u&&u.replaceWith(C('<div class="loco-api loco-api-'+a+'"></div>').append(C('<a class="loco-api-credit" target="_blank" tabindex="-1"></a>').attr("href",l).text(c)).append(C("<blockquote "+f+"></blockquote>").text(n||"FAILED")).append(d)),++w===b&&(m&&m.dialog("option","title",p._("Suggested translations")+" — "+o.label),g+=w),0===i&&d.focus()}function v(t){m&&null==t&&m.dialog("close"),y=m=null,C(S).off("keydown",e)}function i(e){return function(t,n,o){a(t,u[e.getId()]=n,o,e)}}var m=(z=z||O("loco-apis-hint","<div></div>")).html("").append(C('<div class="loco-api"><p>Source text:</p></div>').append(C('<blockquote lang="en"></blockquote>').text(o))).dialog("option","title",p._("Loading suggestions")+"...").off("dialogclose").on("dialogclose",v).dialog("open"),r=t.translation(n);r&&C('<div class="loco-api"><p>Current translation:</p></div>').append(C("<blockquote "+f+"></blockquote>").text(r)).append(C('<button class="button"></button>').attr("tabindex",String(++g)).text(p._("Keep this translation")).on("click",function(t){t.preventDefault(),v()})).appendTo(m);var l,s,h=q(),b=h.length,c=-1,u=j[o]||(j[o]={}),y={},w=0,x={};for(;++c<b;)l=h[c],m.append((d=l,void 0,k=C('<div class="loco-api loco-api-loading"></div>').text("Calling "+d+" ..."),y[d.getId()]=k)),s=l.getId(),x[s]=c,u[s]?a(o,u[s],I,l):l.translate(o,I,i(l));var d,k;C(S).on("keydown",e)}():N()})}function F(t){return t.preventDefault(),B(function(t){t.length?function(){var e,a,i,r=0,l=T,n=!1,s=h.dialog("open"),t=s.find("form"),c=t.find("button.button-primary"),o=C("#loco-job-progress");function u(){c[0].disabled=!0}function d(){c.removeClass("loco-loading")}function p(t){o.text(t)}function f(t){var n=function(t){for(var n,o=q(),e=o.length,a=-1;++a<e;)if((n=o[a]).getId()===t)return n;_.notices.error("No "+t+" client")}(C(t.api).val()),o=t.existing.checked;p("Calculating...."),(e=n.createJob()).init(y,o),a=n.toString(),p(b(l._("%s unique source strings."),e.length.format(0))+" "+b(l._("%s characters will be sent for translation."),e.chars.format(0))),e.length?c[0].disabled=!1:u(),i=null}function g(t){e&&(n&&t.fuzzy(0,!0),D.pasteMessage(t),t===D.active&&D.setStatus(t),D.unsave(t,0),r++)}function v(t,n){var o=n?100*t/n:0;p(b(l._("Translation progress %s%%"),o.format(0)))}function m(){if(d(),e&&i){var t=i.todo();t&&_.notices.warn(b(l._n("Translation job aborted with one string remaining","Translation job aborted with %s strings remaining",t),t.format(0))).slow();var n=[],o=i.did();o&&n.push(b(l._n("%s string translated via %s","%s strings translated via %s",o),o.format(0),a)),r?n.push(b(l._n("%s string updated","%s strings updated",r),r.format(0))):n.push(l._("Nothing needed updating")),_.notices.success(n.join(". ")).slow(),i=e=null}r&&(Y(),D.rebuildSearch()),s&&(s.off("dialogclose").dialog("close"),s=null),D.fire("poAuto")}d(),u(),_.notices.clear(),t.off("submit change"),f(t[0]),t.on("change",function(t){var n=t.target,o=n.name;return"api"!==o&&"existing"!==o||f(n.form),!0}).on("submit",function(t){t.preventDefault(),c.addClass("loco-loading"),u(),v(r=0),n=t.target.fuzzy.checked,i=e.dispatch().done(m).each(g).prog(v).stat()}),s.off("dialogclose").on("dialogclose",function(){e.abort(),s=null,m()})}():N()}),!1}function N(){l?l.dialog("open"):_.notices.error("Logic error. Unconfigured API modal missing")}function R(n){var t=C.extend({locale:String(y.locale()||"")},a||{});v&&v.applyCreds(t),o?(t=function(t){var n,o=new FormData;for(n in t)t.hasOwnProperty(n)&&o.append(n,t[n]);return o}(t)).append("po",new Blob([String(y)],{type:"application/x-gettext"}),String(t.path).split("/").pop()||"untitled.po"):t.data=String(y),_.ajax.post("save",t,function(t){n&&n(),D.save(!0),C("#loco-po-modified").text(t.datetime||"[datetime error]")},n)}function H(){return T._("Your changes will be lost if you continue without saving")}function $(e,a){return e.disabled=!1,C(e).click(function(t){var n=e.form,o=d;return"binary"===a&&(o=o.replace(/\.po$/,".mo")),n.path.value=o,n.source.value=y.toString(),!0}),!0}function W(t){return t.preventDefault(),!1}function Y(){var t=T,n=D.stats(),o=n.t,e=n.f,a=n.u,i=b(t._n("1 string","%s strings",o),o.format(0)),r=[];I&&(i=b(t._("%s%% translated"),n.p.replace("%",""))+", "+i,e&&r.push(b(t._("%s fuzzy"),e.format(0))),a&&r.push(b(t._("%s untranslated"),a.format(0))),r.length&&(i+=" ("+r.join(", ")+")")),C("#loco-po-status").text(i)}}(window,window.jQuery); !function(k,C){var _=k.loco,i=_&&_.conf,u=document.getElementById("loco-editor-inner");if(_&&i&&u){var D,r,t,z,m,l,d=!!i.WP_DEBUG,s=_.po.ref&&_.po.ref.init(_,i),p=null,a=null,o=i.multipart,T=_.l10n,b=_.string.sprintf,I=i.locale,y=_.po.init(I).wrap(i.powrap),c=!I,n=document.getElementById("loco-actions"),f=i.popath,g=i.potpath,v=String(i.syncmode).toLowerCase(),e=document.getElementById("loco-fs"),h=e&&_.fs.init(e),w=i.readonly,x=!w,j={},S=0,M={my:"top",at:"top",of:"#loco-content"};!o||k.FormData&&k.Blob||(o=!1,_.notices.warn("Your browser doesn't support Ajax file uploads. Falling back to standard postdata")),s||_.notices.warn("admin.js is out of date. Please empty your browser cache and reload the page.");var L,E,U=(E=parseInt(C(u).css("min-height")||0),function(){var t=function(t,n){for(var o=t.offsetTop||0;(t=t.offsetParent)&&t!==n;)o+=t.offsetTop||0;return o}(u,document.body),n=k.innerHeight,o=Math.max(E,n-t-20);L!==o&&(u.style.height=String(o)+"px",L=o)});U(),C(k).resize(U),u.innerHTML="",D=_.po.ed.init(u).localise(T),_.po.kbd.init(D).add("save",x?function(){D.dirty&&H()}:Y).add("hint",I&&x&&F||Y).enable("copy","clear","enter","next","prev","fuzzy","save","invis","hint");var P={save:x&&function(n){function o(){n.disabled=!0}function t(){n.disabled=!1}function e(){t(),C(n).removeClass("loco-loading")}return n,D.on("poUnsaved",function(){t(),C(n).addClass("button-primary")}).on("poSave",function(){o(),C(n).removeClass("button-primary")}),a=C.extend({path:f},i.project||{}),C(n).click(function(t){return t.preventDefault(),o(),C(n).addClass("loco-loading"),H(e),!1}),!0},sync:x&&function(n){var t=i.project;if(t){function o(){n.disabled=!0}function e(){n.disabled=!1}function a(){e(),C(n).removeClass("loco-loading")}D.on("poUnsaved",function(){o()}).on("poSave",function(){e()}),p={bundle:t.bundle,domain:t.domain,type:c?"pot":"po",path:f||"",sync:g||"",strip:"pot"===v?"1":""},C(n).click(function(t){return t.preventDefault(),o(),C(n).addClass("loco-loading"),q(a),!1}),e()}return!0},revert:function(t){return D.on("poUnsaved",function(){t.disabled=!1}).on("poSave",function(){t.disabled=!0}),C(t).click(function(t){return t.preventDefault(),location.reload(),!1}),!0},invs:function(t){var o=C(t);return t.disabled=!1,D.on("poInvs",function(t,n){o[n?"addClass":"removeClass"]("inverted")}),o.click(function(t){return t.preventDefault(),D.setInvs(!D.getInvs()),!1}),_.tooltip.init(o),!0},code:function(t){var o=C(t);return t.disabled=!1,o.click(function(t){t.preventDefault();var n=!D.getMono();return o[n?"addClass":"removeClass"]("inverted"),D.setMono(n),!1}),_.tooltip.init(o),!0},source:W,binary:c?null:W};c?(P.add=x&&function(t){return t.disabled=!1,C(t).click(function(t){t.preventDefault();var n,o=1,e=/(\d+)$/;for(n="New message";y.get(n);)o=e.exec(n)?Math.max(o,RegExp.$1):o,n="New message "+ ++o;return D.add(n),!1}),!0},P.del=x&&function(t){return t.disabled=!1,C(t).click(function(t){return t.preventDefault(),D.del(),!1}),!0}):P.auto=function(t){function n(){t.disabled=!1}return D.on("poUnsaved",function(){t.disabled=!0}).on("poSave poAuto",function(){n()}),C(t).click(N),n(),!0},C("#loco-editor > nav .button").each(function(t,n){var o=n.getAttribute("data-loco"),e=P[o];e&&e(n,o)||C(n).addClass("loco-noop")}),C(n).submit(Y),function(n){function e(t){C(n.parentNode)[t||null==t?"removeClass":"addClass"]("invalid")}D.searchable(_.fulltext.init()),n.disabled=!1,n.value="";var a=_.watchtext(n,function(t){e(D.filter(t,!0))});D.on("poFilter",function(t,n,o){a.val(n||""),e(o)}).on("poMerge",function(t,n){var o=a.val();o&&D.filter(o)})}(document.getElementById("loco-search")),D.on("poUnsaved",function(){k.onbeforeunload=$}).on("poSave",function(){G(),k.onbeforeunload=null}).on("poHint",F).on("poUpdate",G).on("poMeta",function(t,n){var o,e,a=(e="CODE",(o=n).tagName===e?o:o.getElementsByTagName(e)[0]);return!a||!s||(s.load(a.textContent),t.preventDefault(),!1)}),y.load(i.podata),D.load(y),(I=D.targetLocale)?I.isRTL()&&C(u).addClass("trg-rtl"):D.unlock(),G(),delete _.conf,i=P=null}function q(c){_.ajax.post("sync",p,function(t){var n=[],o=t.pot,e=t.po,a=t.done||{add:[],del:[],fuz:[]},i=a.add.length,r=a.del.length,l=a.fuz.length,s=T;y.clear().load(e),D.load(y),i||r||l?(o?n.push(b(s._("Merged from %s"),o)):n.push(s._("Merged from source code")),i&&n.push(b(s._n("1 new string added","%s new strings added",i),i)),r&&n.push(b(s._n("1 obsolete string removed","%s obsolete strings removed",r),r)),l&&n.push(b(s._n("1 string marked Fuzzy","%s strings marked Fuzzy",l),l)),C(u).trigger("poUnsaved",[]),G(),d&&k.console&&function(t,n){var o=-1,e=n.add.length;for(;++o<e;)t.log(" + "+String(n.add[o]));for(e=n.del.length,o=0;o<e;o++)t.log(" - "+String(n.del[o]));for(e=n.fuz.length,o=0;o<e;o++)t.log(" ~ "+String(n.fuz[o]))}(console,a)):o?n.push(b(s._("Strings up to date with %s"),o)):n.push(s._("Strings up to date with source code")),_.notices.success(n.join(". ")),C(u).trigger("poMerge",[t]),c&&c()},c)}function B(){return t=t||function(){for(var t,n=-1,o=[],e=r,a=e.length;++n<a;)try{t=e[n],o.push(_.apis.create(t))}catch(t){_.notices.error(String(t))}return o}()}function O(e){var a;function i(){return(new Date).getTime()}c||w?_.notices.error("Logic error. APIs not available in current mode"):null==r||0===r.length||10<Math.round((i()-S)/1e3)?(l&&l.remove(),l=null,m&&m.remove(),m=null,z&&z.remove(),r=z=null,a=C('<div><div class="loco-loading"></div></div>').dialog({dialogClass:"loco-modal loco-modal-no-close",appendTo:"#loco-admin.wrap",title:"Loading..",modal:!0,autoOpen:!0,closeOnEscape:!1,resizable:!1,draggable:!1,position:M,height:200}),_.ajax.get("apis",{locale:String(I)},function(t,n,o){S=i(),0===(r=t&&t.apis||[]).length?l=A("loco-apis-empty",t.html):m=A("loco-apis-batch",t.html),a.remove(),e(r)})):(S=i(),e(r))}function A(t,n){var o=C(n);return o.attr("id",t),o.dialog({dialogClass:"loco-modal",appendTo:"#loco-admin.wrap",title:o.attr("title"),modal:!0,autoOpen:!1,closeOnEscape:!0,resizable:!1,draggable:!1,position:M}),o}function F(){O(function(t){t.length?function(){var p=T,t=D.current(),n=D.getTargetOffset(),o=t&&t.source(null,n),f='lang="'+String(I)+'" dir="'+(I.isRTL()?"RTL":"LTR")+'"',g=99;if(!o)return;function e(t){return!t.isDefaultPrevented()&&(!(0<=(n=t.which-49)&&n<10&&(o=h&&h.find("button.button-primary").eq(n))&&1===o.length)||(t.preventDefault(),t.stopPropagation(),o.click(),!1));var n,o}function a(t,n,o,e){var a=e.getId(),i=x[a],r=String(i+1),l=e.getUrl(),s=p._("Use this translation"),c=String(e),u=y&&y[a],d=C('<button class="button button-primary"></button>').attr("tabindex",String(1+g+i)).on("click",function(e,a){return function(t){t.preventDefault(),t.stopPropagation(),v();var n=D.current(),o=D.getTargetOffset();n&&n.source(null,o)===e?(n.translate(a,o),D.focus().reloadMessage(n)):_.notices.warn("Source changed since suggestion")}}(t,n));d.attr("accesskey",r),1<m.length&&(s+=" ("+r+")"),d.text(s),u&&u.replaceWith(C('<div class="loco-api loco-api-'+a+'"></div>').append(C('<a class="loco-api-credit" target="_blank" tabindex="-1"></a>').attr("href",l).text(c)).append(C("<blockquote "+f+"></blockquote>").text(n||"FAILED")).append(d)),++w===b&&(h&&h.dialog("option","title",p._("Suggested translations")+" — "+o.label),g+=w),0===i&&d.focus()}function v(t){h&&null==t&&h.dialog("close"),y=h=null,C(k).off("keydown",e)}function i(e){return function(t,n,o){a(t,u[e.getId()]=n,o,e)}}var h=(z=z||A("loco-apis-hint","<div></div>")).html("").append(C('<div class="loco-api"><p>Source text:</p></div>').append(C('<blockquote lang="en"></blockquote>').text(o))).dialog("option","title",p._("Loading suggestions")+"...").off("dialogclose").on("dialogclose",v).dialog("open"),r=t.translation(n);r&&C('<div class="loco-api"><p>Current translation:</p></div>').append(C("<blockquote "+f+"></blockquote>").text(r)).append(C('<button class="button"></button>').attr("tabindex",String(++g)).text(p._("Keep this translation")).on("click",function(t){t.preventDefault(),v()})).appendTo(h);var l,s,m=B(),b=m.length,c=-1,u=j[o]||(j[o]={}),y={},w=0,x={};for(;++c<b;)l=m[c],h.append((d=l,void 0,S=C('<div class="loco-api loco-api-loading"></div>').text("Calling "+d+" ..."),y[d.getId()]=S)),s=l.getId(),x[s]=c,u[s]?a(o,u[s],I,l):l.translate(o,I,i(l));var d,S;C(k).on("keydown",e)}():R()})}function N(t){return t.preventDefault(),O(function(t){t.length?function(){var e,a,i,r=0,l=T,n=!1,s=m.dialog("open"),t=s.find("form"),c=t.find("button.button-primary"),o=C("#loco-job-progress");function u(){c[0].disabled=!0}function d(){c.removeClass("loco-loading")}function p(t){o.text(t)}function f(t){var n=function(t){for(var n,o=B(),e=o.length,a=-1;++a<e;)if((n=o[a]).getId()===t)return n;_.notices.error("No "+t+" client")}(C(t.api).val()),o=t.existing.checked;p("Calculating...."),(e=n.createJob()).init(y,o),a=n.toString(),p(b(l._("%s unique source strings."),e.length.format(0))+" "+b(l._("%s characters will be sent for translation."),e.chars.format(0))),e.length?c[0].disabled=!1:u(),i=null}function g(t){e&&(n&&t.fuzzy(0,!0),D.pasteMessage(t),t===D.active&&D.setStatus(t),D.unsave(t,0),r++)}function v(t,n){var o=n?100*t/n:0;p(b(l._("Translation progress %s%%"),o.format(0)))}function h(){if(d(),e&&i){var t=i.todo();t&&_.notices.warn(b(l._n("Translation job aborted with one string remaining","Translation job aborted with %s strings remaining",t),t.format(0))).slow();var n=[],o=i.did();o&&n.push(b(l._n("%s string translated via %s","%s strings translated via %s",o),o.format(0),a)),r?n.push(b(l._n("%s string updated","%s strings updated",r),r.format(0))):n.push(l._("Nothing needed updating")),_.notices.success(n.join(". ")).slow(),i=e=null}r&&(G(),D.rebuildSearch()),s&&(s.off("dialogclose").dialog("close"),s=null),D.fire("poAuto")}d(),u(),_.notices.clear(),t.off("submit change"),f(t[0]),t.on("change",function(t){var n=t.target,o=n.name;return"api"!==o&&"existing"!==o||f(n.form),!0}).on("submit",function(t){t.preventDefault(),c.addClass("loco-loading"),u(),v(r=0),n=t.target.fuzzy.checked,i=e.dispatch().done(h).each(g).prog(v).stat()}),s.off("dialogclose").on("dialogclose",function(){e.abort(),s=null,h()})}():R()}),!1}function R(){l?l.dialog("open"):_.notices.error("Logic error. Unconfigured API modal missing")}function H(n){var t=C.extend({locale:String(y.locale()||"")},a||{});h&&h.applyCreds(t),o?(t=function(t){var n,o=new FormData;for(n in t)t.hasOwnProperty(n)&&o.append(n,t[n]);return o}(t)).append("po",new Blob([String(y)],{type:"application/x-gettext"}),String(t.path).split("/").pop()||"untitled.po"):t.data=String(y),_.ajax.post("save",t,function(t){n&&n(),D.save(!0),C("#loco-po-modified").text(t.datetime||"[datetime error]")},n)}function $(){return T._("Your changes will be lost if you continue without saving")}function W(e,a){return e.disabled=!1,C(e).click(function(t){var n=e.form,o=f;return"binary"===a&&(o=o.replace(/\.po$/,".mo")),n.path.value=o,n.source.value=y.toString(),!0}),!0}function Y(t){return t.preventDefault(),!1}function G(){var t=T,n=D.stats(),o=n.t,e=n.f,a=n.u,i=b(t._n("1 string","%s strings",o),o.format(0)),r=[];I&&(i=b(t._("%s%% translated"),n.p.replace("%",""))+", "+i,e&&r.push(b(t._("%s fuzzy"),e.format(0))),a&&r.push(b(t._("%s untranslated"),a.format(0))),r.length&&(i+=" ("+r.join(", ")+")")),C("#loco-po-status").text(i)}}(window,window.jQuery);
\ No newline at end of file \ No newline at end of file
...@@ -3,8 +3,8 @@ Contributors: timwhitlock ...@@ -3,8 +3,8 @@ Contributors: timwhitlock
Tags: translation, translators, localization, localisation, l10n, i18n, Gettext, PO, MO, productivity, multilingual, internationalization Tags: translation, translators, localization, localisation, l10n, i18n, Gettext, PO, MO, productivity, multilingual, internationalization
Requires at least: 4.1 Requires at least: 4.1
Requires PHP: 5.2.4 Requires PHP: 5.2.4
Tested up to: 5.5.1 Tested up to: 5.5.3
Stable tag: 2.4.4 Stable tag: 2.4.5
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html License URI: http://www.gnu.org/licenses/gpl-2.0.html
...@@ -100,6 +100,14 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http ...@@ -100,6 +100,14 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http
== Changelog == == Changelog ==
= 2.4.5 =
* Added WP-CLI sync and extract commands
* Fixed {locale} placeholder bug introduced in 2.4.4
* Improved handling of invalid character encodings
* Sync (msgmerge) moved to back end
* New fuzzy matching with fuzziness setting
* Bumped WordPress version to 5.5.3
= 2.4.4 = = 2.4.4 =
* Added PO file upload feature * Added PO file upload feature
* Added download button to file info page * Added download button to file info page
...@@ -377,7 +385,7 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http ...@@ -377,7 +385,7 @@ We don't collect your data or snoop on you. See the [plugin privacy notice](http
== Upgrade Notice == == Upgrade Notice ==
= 2.4.4 = = 2.4.5 =
* Various improvements and bugfixes * Various improvements and bugfixes
......
...@@ -66,7 +66,7 @@ class Loco_admin_bundle_LocaleController extends Loco_mvc_AdminController { ...@@ -66,7 +66,7 @@ class Loco_admin_bundle_LocaleController extends Loco_mvc_AdminController {
$files = $package->findTemplateFiles()->augment($files); $files = $package->findTemplateFiles()->augment($files);
} }
/* @var Loco_fs_File */ /* @var Loco_fs_File $file */
foreach( $files as $file ){ foreach( $files as $file ){
$nfiles++; $nfiles++;
if( 'pot' !== $file->extension() ){ if( 'pot' !== $file->extension() ){
......
...@@ -70,10 +70,12 @@ class Loco_admin_file_EditController extends Loco_admin_file_BaseController { ...@@ -70,10 +70,12 @@ class Loco_admin_file_EditController extends Loco_admin_file_BaseController {
// default is to permit editing of any file // default is to permit editing of any file
$readonly = false; $readonly = false;
// All files must belong to a bundle.
$bundle = $this->getBundle();
// Establish if file belongs to a configured project // Establish if file belongs to a configured project
try { try {
$bundle = $this->getBundle();
$project = $this->getProject(); $project = $this->getProject();
} }
// Fine if not, this just means sync isn't possible. // Fine if not, this just means sync isn't possible.
......
...@@ -272,7 +272,7 @@ class Loco_admin_init_InitPoController extends Loco_admin_bundle_BaseController ...@@ -272,7 +272,7 @@ class Loco_admin_init_InitPoController extends Loco_admin_bundle_BaseController
$writable = false; $writable = false;
$disabled = true; $disabled = true;
} }
$suffix = '-'.$pofile->getSuffix().'.po'; $suffix = $pofile->getSuffix().'.po';
$choice = new Loco_mvc_ViewParams( array ( $choice = new Loco_mvc_ViewParams( array (
'checked' => '', 'checked' => '',
'writable' => $writable, 'writable' => $writable,
...@@ -280,7 +280,7 @@ class Loco_admin_init_InitPoController extends Loco_admin_bundle_BaseController ...@@ -280,7 +280,7 @@ class Loco_admin_init_InitPoController extends Loco_admin_bundle_BaseController
'systype' => $systype, 'systype' => $systype,
'parent' => Loco_mvc_FileParams::create( $parent ), 'parent' => Loco_mvc_FileParams::create( $parent ),
'hidden' => $pofile->getRelativePath($content_dir), 'hidden' => $pofile->getRelativePath($content_dir),
'holder' => str_replace( $suffix, '-<span>{locale}</span>.po', $pofile->basename() ), 'holder' => str_replace( $suffix, '<span>{locale}</span>.po', $pofile->basename() ),
) ); ) );
$sortable[] = $choice; $sortable[] = $choice;
$locations[$typeId]['paths'][] = $choice; $locations[$typeId]['paths'][] = $choice;
......
...@@ -51,17 +51,6 @@ class Loco_admin_init_InitPotController extends Loco_admin_bundle_BaseController ...@@ -51,17 +51,6 @@ class Loco_admin_init_InitPotController extends Loco_admin_bundle_BaseController
// Establish default POT path whether it exists or not // Establish default POT path whether it exists or not
$pot = $project->getPot(); $pot = $project->getPot();
while( ! $pot ){
$name = ( $slug ? $slug : $domain ).'.pot';
/* @var $dir Loco_fs_Directory */
foreach( $project->getConfiguredTargets() as $dir ){
$pot = new Loco_fs_File( $dir->getPath().'/'.$name );
break 2;
}
// unlikely to have no configured targets, but possible ... so default to standard
$pot = new Loco_fs_File( $bundle->getDirectoryPath().'/languages/'.$name );
break;
}
// POT should actually not exist at this stage. It should be edited instead. // POT should actually not exist at this stage. It should be edited instead.
if( $pot->exists() ){ if( $pot->exists() ){
......
...@@ -69,7 +69,7 @@ class Loco_admin_init_UploadController extends Loco_admin_bundle_BaseController ...@@ -69,7 +69,7 @@ class Loco_admin_init_UploadController extends Loco_admin_bundle_BaseController
} }
$locations[$typeId]['paths'][] = new Loco_mvc_ViewParams( array( $locations[$typeId]['paths'][] = new Loco_mvc_ViewParams( array(
'parent' => Loco_mvc_FileParams::create($parent), 'parent' => Loco_mvc_FileParams::create($parent),
'holder' => str_replace('-zxx.po','-{locale}</span>.po', $pofile->basename() ), 'holder' => str_replace('zxx.po','{locale}</span>.po', $pofile->basename() ),
) ); ) );
} }
// we don't know what the specifics will be until a location is chosen and a file is presented. // we don't know what the specifics will be until a location is chosen and a file is presented.
......
...@@ -13,9 +13,7 @@ class Loco_admin_list_ThemesController extends Loco_admin_list_BaseController { ...@@ -13,9 +13,7 @@ class Loco_admin_list_ThemesController extends Loco_admin_list_BaseController {
$this->set('type', 'theme' ); $this->set('type', 'theme' );
$this->set('title', __( 'Translate themes', 'loco-translate' ) ); $this->set('title', __( 'Translate themes', 'loco-translate' ) );
/* @var $theme WP_Theme */ foreach( Loco_package_Theme::getAll() as $bundle ){
foreach( wp_get_themes() as $theme ){
$bundle = Loco_package_Theme::create( $theme->get_stylesheet() );
$this->addBundle( $bundle ); $this->addBundle( $bundle );
} }
......
...@@ -40,7 +40,7 @@ class Loco_ajax_DownloadController extends Loco_mvc_AjaxController { ...@@ -40,7 +40,7 @@ class Loco_ajax_DownloadController extends Loco_mvc_AjaxController {
$has_bom = "\xEF\xBB\xBF" === substr($raw,0,3); $has_bom = "\xEF\xBB\xBF" === substr($raw,0,3);
$use_bom = (bool) Loco_data_Settings::get()->po_utf8_bom; $use_bom = (bool) Loco_data_Settings::get()->po_utf8_bom;
// only alter file if valid UTF-8. Deferring detection overhead until required // only alter file if valid UTF-8. Deferring detection overhead until required
if( $has_bom !== $use_bom && 'UTF-8' === mb_detect_encoding( $raw, array('UTF-8','ISO-8859-1'), true ) ){ if( $has_bom !== $use_bom && preg_match('//u',$raw) ){
if( $use_bom ){ if( $use_bom ){
$raw = "\xEF\xBB\xBF".$raw; // prepend $raw = "\xEF\xBB\xBF".$raw; // prepend
} }
...@@ -52,6 +52,5 @@ class Loco_ajax_DownloadController extends Loco_mvc_AjaxController { ...@@ -52,6 +52,5 @@ class Loco_ajax_DownloadController extends Loco_mvc_AjaxController {
return $raw; return $raw;
} }
}
}
\ No newline at end of file
...@@ -77,14 +77,17 @@ class Loco_ajax_MsginitController extends Loco_ajax_common_BundleController { ...@@ -77,14 +77,17 @@ class Loco_ajax_MsginitController extends Loco_ajax_common_BundleController {
} }
} }
// else parse POT file if project defines one that exists // else parse POT file if project defines one that exists
else if( ( $potfile = $project->getPot() ) && $potfile->exists() ){
$data = Loco_gettext_Data::load($potfile);
}
// else extract directly from source code, assuming domain passed though from front end
else { else {
$extr = new Loco_gettext_Extraction( $bundle ); $potfile = $project->getPot();
$data = $extr->addProject($project)->includeMeta()->getTemplate($domain); if( $potfile->exists() ){
$potfile = null; $data = Loco_gettext_Data::load($potfile);
}
// else extract directly from source code, assuming domain passed though from front end
else {
$extr = new Loco_gettext_Extraction( $bundle );
$data = $extr->addProject($project)->includeMeta()->getTemplate($domain);
$potfile = null;
}
} }
// Let template define Project-Id-Version, else set header to current project name // Let template define Project-Id-Version, else set header to current project name
......
<?php <?php /** @noinspection DuplicatedCode */
/** /**
* Ajax "sync" route. * Ajax "sync" route.
* Extracts strings from source (POT or code) and returns to the browser for in-editor merge. * Extracts strings from source (POT or code) and returns to the browser for in-editor merge.
...@@ -17,21 +18,28 @@ class Loco_ajax_SyncController extends Loco_mvc_AjaxController { ...@@ -17,21 +18,28 @@ class Loco_ajax_SyncController extends Loco_mvc_AjaxController {
if( ! $project instanceof Loco_package_Project ){ if( ! $project instanceof Loco_package_Project ){
throw new Loco_error_Exception('No such project '.$post->domain); throw new Loco_error_Exception('No such project '.$post->domain);
} }
// Merging on back end is only required if existing target file exists.
// Currently it always will and the editor is not permitted to contain unsaved changes when syncing.
if( ! $post->has('path') ){
throw new Loco_error_Exception('path argument required');
}
$file = new Loco_fs_File( $post->path ); $file = new Loco_fs_File( $post->path );
$base = loco_constant('WP_CONTENT_DIR'); $base = loco_constant('WP_CONTENT_DIR');
$file->normalize($base); $file->normalize($base);
$target = Loco_gettext_Data::load($file);
// POT file always synced with source code (even if a PO being used as POT)
if( 'pot' === $post->type ){ // POT file always synced with source code
$type = $post->type;
if( 'pot' === $type ){
$potfile = null; $potfile = null;
} }
// allow post data to force a template file path // allow front end to configure source file. (will have come from $target headers)
else if( $path = $post->sync ){ else if( $post->has('sync') ){
$potfile = new Loco_fs_File($path); $potfile = new Loco_fs_File( $post->sync );
$potfile->normalize($base); $potfile->normalize($base);
} }
// else use project-configured template if one is defined // else use project-configured template path
else { else {
$potfile = $project->getPot(); $potfile = $project->getPot();
} }
...@@ -43,22 +51,21 @@ class Loco_ajax_SyncController extends Loco_mvc_AjaxController { ...@@ -43,22 +51,21 @@ class Loco_ajax_SyncController extends Loco_mvc_AjaxController {
$potfile = null; $potfile = null;
} }
// sync with POT if it exists // Parse existing POT for source
if( $potfile ){ if( $potfile ){
$this->set('pot', $potfile->basename() ); $this->set('pot', $potfile->basename() );
try { try {
$data = Loco_gettext_Data::load($potfile); $source = Loco_gettext_Data::load($potfile);
} }
catch( Exception $e ){ catch( Exception $e ){
// translators: Where %s is the name of the invalid POT file // translators: Where %s is the name of the invalid POT file
throw new Loco_error_ParseException( sprintf( __('Translation template is invalid (%s)','loco-translate'), $potfile->basename() ) ); throw new Loco_error_ParseException( sprintf( __('Translation template is invalid (%s)','loco-translate'), $potfile->basename() ) );
} }
// strip msgstr fields from PO files if template is user-defined and "copy translations" was not selected. // Only copy msgstr fields from source if it's a user-defined PO template and "copy translations" was selected.
if( '1' === $post->strip ){ $strip = (bool) $post->strip;
$data->strip(); $translate = 'pot' !== $potfile->extension() && ! $strip;
}
} }
// else sync with source code // else extract POT from source code
else { else {
$this->set('pot', '' ); $this->set('pot', '' );
$domain = (string) $project->getDomain(); $domain = (string) $project->getDomain();
...@@ -75,11 +82,79 @@ class Loco_ajax_SyncController extends Loco_mvc_AjaxController { ...@@ -75,11 +82,79 @@ class Loco_ajax_SyncController extends Loco_mvc_AjaxController {
// not failing, just warning. Nothing will be saved until user saves editor state // not failing, just warning. Nothing will be saved until user saves editor state
Loco_error_AdminNotices::warn( $text ); Loco_error_AdminNotices::warn( $text );
} }
// OK to return available strings // Have source strings. These cannot contain any translations.
$data = $extr->includeMeta()->getTemplate($domain); $source = $extr->includeMeta()->getTemplate($domain);
$translate = false;
$strip = false;
} }
$this->set( 'po', $data->jsonSerialize() ); // establish on back end what strings will be added, removed, and which could be fuzzy-matches
$ntotal = 0;
$nmatched = 0;
$added = array();
$dropped = array();
$fuzzy = array();
// add latest valid sources to matching instance
$matcher = new LocoFuzzyMatcher;
/* @var LocoPoMessage $new */
foreach( $source as $new ){
$matcher->add($new);
$ntotal++;
}
// Fuzzy matching only applies to syncing PO files. POT files will always do hard sync (add/remove)
if( 'po' === $type ){
$fuzziness = Loco_data_Settings::get()->fuzziness;
$matcher->setFuzziness( (string) $fuzziness );
}
else {
$matcher->setFuzziness('0');
}
// update matches sources, deferring unmatched for deferred fuzzy match
$merged = clone $target;
$merged->clear();
/* @var LocoPoMessage $old */
foreach( $target as $old ){
$new = $matcher->match($old);
// if existing source is still valid, merge any changes
if( $new instanceof LocoPoMessage ){
$p = clone $old;
$p->merge($new,$translate);
$merged->push($p);
$nmatched++;
}
}
// Attempt fuzzy matching after all exact matches have been processed
if( $nmatched !== $ntotal ){
foreach( $matcher->getFuzzyMatches() as $pair ){
list($old,$new) = $pair;
$p = clone $old;
$p->merge($new);
$merged->push($p);
$fuzzy[] = $p->getKey();
}
// Any unmatched strings remaining are NEW
/* @var LocoPoMessage $new */
foreach( $matcher->unmatched() as $new ){
$p = clone $new;
$strip and $p->strip();
$merged->push($p);
$added[] = $p->getKey();
}
// any deferred matches not resolved are dropped
/* @var LocoPoMessage $old */
foreach( $matcher->redundant() as $old ){
$dropped[] = $old->getKey();
}
}
// return to JavaScript with stats in the same form as old front end merge
$this->set( 'done', array (
'add' => $added,
'fuz' => $fuzzy,
'del' => $dropped,
) );
$merged->sort();
$this->set( 'po', $merged->jsonSerialize() );
return parent::render(); return parent::render();
} }
......
<?php
/**
* Loco Translate commands
*/
class Loco_cli_Commands {
/**
* Sync translation files with the available source strings
*
* ## OPTIONS
*
* [<filter>]
* : Restrict to a type of bundle (plugins|themes|core) or a specific Text Domain
*
* [--locale=<code>]
* : Restrict to one or more locales. Separate multiple codes with commas.
*
* [--fuzziness=<percent>]
* : Override plugin settings for fuzzy matching tolerance (0-100).
*
* [--noop]
* : Specify dry run. Makes no changes on disk.
*
* ## EXAMPLES
*
* wp loco sync plugins
*
*
* @param string[]
* @param string[]
* @codeCoverageIgnore
*/
public function sync( $args, $opts ){
if( array_key_exists('fuzziness',$opts) ){
Loco_data_Settings::get()->fuzziness = (int) $opts['fuzziness'];
}
try {
Loco_cli_SyncCommand::run (
Loco_cli_Utils::collectProjects( isset($args[0]) ? $args[0] : '' ),
Loco_cli_Utils::collectLocales( isset($opts['locale']) ? $opts['locale'] : '' ),
Loco_cli_Utils::bool($opts,'noop')
);
}
catch( Loco_error_Exception $e ){
WP_CLI::error( $e->getMessage() );
}
}
/**
* Extract available source strings
*
* ## OPTIONS
*
* [<filter>]
* : Restrict to a type of bundle (plugins|themes|core) or a specific Text Domain
*
* [--maxsize=<size>]
* : Override plugin settings for maximum PHP file size
*
* [--noop]
* : Specify dry run. Makes no changes on disk.
*
* ## EXAMPLES
*
* wp loco extract core --maxsize=400K
*
* @param string[]
* @param string[]
* @codeCoverageIgnore
*/
public function extract( $args, $opts ){
try {
if( array_key_exists('maxsize',$opts) ){
Loco_data_Settings::get()->max_php_size = $opts['maxsize'];
}
Loco_cli_ExtractCommand::run (
Loco_cli_Utils::collectProjects( isset($args[0]) ? $args[0] : '' ),
Loco_cli_Utils::bool($opts,'noop')
);
}
catch( Loco_error_Exception $e ){
WP_CLI::error( $e->getMessage() );
}
}
}
\ No newline at end of file
<?php
/**
* Called from Loco_cli_Commands::extract
*/
abstract class Loco_cli_ExtractCommand {
/**
* @param Loco_package_Project[] project filter
* @param bool whether dry run
*/
public static function run( array $projects, $noop = true ){
// track total number of POT files synced
$updated = 0;
$content_dir = loco_constant('WP_CONTENT_DIR');
/* @var Loco_package_Project $project */
foreach( $projects as $project ){
$id = rtrim( $project->getId(), '.' );
WP_CLI::log( sprintf('Extracting "%s" (%s)',$project->getName(),$id) );
// POT file may or may not exist currently
$potfile = $project->getPot();
if( ! $potfile ){
WP_CLI::warning('Skipping undefined POT');
continue;
}
if( $potfile->locked() ){
WP_CLI::warning('Skipping unwritable POT');
Loco_cli_Utils::tabulateFiles( $potfile->getParent(), $potfile );
continue;
}
// Do extraction and grab only given domain's strings
$ext = new Loco_gettext_Extraction( $project->getBundle() );
$domain = $project->getDomain()->getName();
$data = $ext->addProject($project)->includeMeta()->getTemplate( $domain );
Loco_cli_Utils::debug('Extraction OK, %u strings', count($data) );
$list = $ext->getSkipped();
if( $list ){
$current = Loco_data_Settings::get()->max_php_size;
$suggest = ceil( $ext->getMaxPhpSize() / 1024 );
WP_CLI::warning(sprintf('%u source files skipped over %s. Consider running with --maxsize=%uK',count($list),$current,$suggest) );
foreach( $list as $file ) {
$f = new Loco_mvc_FileParams(array(),$file);
Loco_cli_Utils::debug('%s (%s)', $f->relpath, $f->size );
}
}
// if POT exists check if update is necessary.
$data->sort();
if( $potfile->exists() ){
try {
Loco_cli_Utils::debug('Checking if sources have changed since '.date('c',$potfile->modified()) );
$prev = Loco_gettext_Data::fromSource( $potfile->getContents() );
if( $prev->equal($data) ){
WP_CLI::log('No update required for '.$potfile->basename() );
continue;
}
}
catch( Loco_error_ParseException $e ){
Loco_cli_Utils::debug( $e->getMessage().' in '.$potfile->basename() );
}
}
if( $noop ){
WP_CLI::success( sprintf('**DRY RUN** would update %s', $potfile->basename() ) );
continue;
}
// additional headers to set in new POT file
$head = $data->getHeaders();
$head['Project-Id-Version'] = $project->getName();
// write POT file to disk returning byte length
Loco_cli_Utils::debug('Writing POT file...');
$bytes = $potfile->putContents( $data->msgcat(false) );
Loco_cli_Utils::debug(' %u bytes written to %s',$bytes, $potfile->getRelativePath($content_dir) );
WP_CLI::success( sprintf('Updated %s', $potfile->basename() ) );
$updated++;
}
// sync summary
if( 0 === $updated ){
WP_CLI::log('Nothing updated');
}
else {
WP_CLI::success( sprintf('%u POT files written',$updated) );
}
}
}
\ No newline at end of file
<?php /** @noinspection DuplicatedCode */
/**
* Called from Loco_cli_Commands::sync
*/
abstract class Loco_cli_SyncCommand {
/**
* @param Loco_package_Project[] project filter
* @param Loco_Locale[] locale filter
* @param bool whether dry run
*/
public static function run( array $projects, array $locales, $noop = true ){
// CLI runs all disk operations directly. No remote authorization here currently.
$fs = new Loco_api_WordPressFileSystem;
$content_dir = loco_constant('WP_CONTENT_DIR');
// track total number of PO files synced
$updated = 0;
/* @var Loco_package_Project $project */
foreach( $projects as $project ){
$id = rtrim( $project->getId(), '.' );
WP_CLI::log( sprintf('Syncing "%s" (%s)',$project->getName(),$id) );
// Check if project has POT, which will be used as default template unless PO overrides
$pot = null;
$potfile = $project->getPot();
if( $potfile && $potfile->exists() ){
Loco_cli_Utils::debug('Parsing template: %s',$potfile->getRelativePath($content_dir));
try {
$pot = Loco_gettext_Data::fromSource( $potfile->getContents() );
}
catch( Loco_error_ParseException $e ){
WP_CLI::error( $e->getMessage().' in '.$potfile->getRelativePath($content_dir), false );
$potfile = null;
}
}
/* @var Loco_fs_LocaleFile $pofile */
$pofiles = $project->findLocaleFiles('po');
foreach( $pofiles as $pofile ){
$locale = $pofile->getLocale();
$tag = (string) $locale;
if( $locales && ! array_key_exists($tag,$locales) ){
continue;
}
// Preempt write errors and print useful file mode info
$mofile = $pofile->cloneExtension('mo');
if( ! $pofile->writable() || $mofile->locked() ){
WP_CLI::warning('Skipping unwritable: '.$pofile->filename() );
Loco_cli_Utils::tabulateFiles( $pofile->getParent(), $pofile, $mofile );
continue;
}
// Parsing candidate PO file (definitions)
Loco_cli_Utils::debug('Parsing PO: %s',$pofile->getRelativePath($content_dir));
try {
$def = Loco_gettext_Data::fromSource( $pofile->getContents() );
}
catch( Loco_error_ParseException $e ){
WP_CLI::error( $e->getMessage().' in '.$pofile->getRelativePath($content_dir), false );
continue;
}
// Check if PO defines alternative template (reference)
$ref = $pot;
$translate = true;
$head = $def->getHeaders();
if( $head->has('X-Loco-Template') ){
$ref = null;
$potfile = new Loco_fs_File( $head['X-Loco-Template'] );
$potfile->normalize( $project->getBundle()->getDirectoryPath() );
if( $potfile->exists() ){
try {
Loco_cli_Utils::debug('> Parsing alternative template: %s',$potfile->getRelativePath($content_dir) );
$ref = Loco_gettext_Data::fromSource( $potfile->getContents() );
// Default sync behaviour is to copy msgstr fields unless in POT mode
if( $head->has('X-Loco-Template-Mode') && 'POT' === $head['X-Loco-Template-Mode'] ){
$translate = false;
}
}
catch( Loco_error_ParseException $e ){
WP_CLI::error( $e->getMessage().' in '.$potfile->getRelativePath($content_dir), false );
}
}
else {
Loco_cli_Utils::debug('Template not found (%s)', $potfile->basename() );
}
}
// Perform merge if we have a reference file
if( $ref ){
Loco_cli_Utils::debug('Merging %s <- %s', $pofile->basename(), $potfile->basename() );
$po = self::msgmerge( $def, $ref, $translate );
}
else {
WP_CLI::warning( sprintf('Skipping %s; no valid translation template',$pofile->getRelativePath($content_dir) ) );
continue;
}
// File is synced, but may be identical
$po->sort();
if( $po->equal($def) ){
WP_CLI::log( sprintf('No update required for %s', $pofile->filename() ) );
continue;
}
if( $noop ){
WP_CLI::success( sprintf('**DRY RUN** would update %s', $pofile->filename() ) );
continue;
}
try {
// file is different so make a backup before overwriting
$backups = new Loco_fs_Revisions($pofile);
if( $backups->rotate($fs) ){
Loco_cli_Utils::debug('+ saved backup file of %s',$pofile->basename() );
}
// write new PO
$po->localize($locale);
$bytes = $pofile->putContents( $po->msgcat() );
Loco_cli_Utils::debug('+ %u bytes written to %s',$bytes, $pofile->basename());
$updated++;
// compile MO
$bytes = $mofile->putContents( $po->msgfmt() );
Loco_cli_Utils::debug('+ %u bytes written to %s',$bytes, $mofile->basename());
// Done PO/MO pair
WP_CLI::success( sprintf('Updated %s', $pofile->filename() ) );
}
catch( Loco_error_WriteException $e ){
WP_CLI::error( $e->getMessage(), false );
}
}
}
// sync summary
if( 0 === $updated ){
WP_CLI::log('Nothing updated');
}
else {
WP_CLI::success( sprintf('%u PO files synced',$updated) );
}
}
/**
* @param Loco_gettext_Data Existing PO file to MODIFY (definitions)
* @param Loco_gettext_Data Latest POT file, being synced in (reference)
* @param bool whether to merge translations in addition to sources
* @return Loco_gettext_Data Merged file replacing $po
*/
private static function msgmerge( Loco_gettext_Data $po, Loco_gettext_Data $pot, $translate = false ){
$ntotal = 0;
$nmatched = 0;
$nfuzzy = 0;
$nadded = 0;
// add latest valid sources to matching instance
$matcher = new LocoFuzzyMatcher;
/* @var LocoPoMessage $new */
foreach( $pot as $new ){
$ntotal++;
$matcher->add($new);
}
// Get fuzzy matching tolerance from plugin settings, can be set temporarily in command line
$fuzziness = Loco_data_Settings::get()->fuzziness;
$matcher->setFuzziness( (string) $fuzziness );
// update matches sources, deferring unmatched for deferred fuzzy match
$merged = clone $po;
$merged->clear();
/* @var LocoPoMessage $old */
foreach( $po as $old ){
$new = $matcher->match($old);
// if existing source is still valid, merge any changes
if( $new instanceof LocoPoMessage ){
$p = clone $old;
$p->merge($new,$translate);
$merged->push($p);
$nmatched += $p->countForms();
}
}
// We can quit early if all strings were matched
if( $nmatched === $ntotal ){
Loco_cli_Utils::debug('> %u identical sources',$ntotal);
return $merged;
}
// Attempt fuzzy matching after all exact matches have been processed
foreach( $matcher->getFuzzyMatches() as $pair ){
list($old,$new) = $pair;
$p = clone $old;
$p->merge($new);
$merged->push($p);
$nfuzzy += $p->countForms();
Loco_cli_Utils::debug('~ %s', $p['source'] );
}
// Any unmatched strings remaining are NEW
/* @var LocoPoMessage $new */
foreach( $matcher->unmatched() as $new ){
$p = clone $new;
$translate or $p->strip();
$merged->push($p);
$nadded += $p->countForms();
Loco_cli_Utils::debug('+ %s', $p['source'] );
}
// TODO Support --previous to keep old strings, or at least comment them out as #| msgid.....
// number of strings dropped is previous total minus those matched
$ndropped = $po->count() - ( $nmatched + $nfuzzy );
Loco_cli_Utils::debug('> unchanged:%u added:%u fuzzy:%u dropped:%u', $nmatched, $nadded, $nfuzzy, $ndropped );
return $merged;
}
}
\ No newline at end of file
<?php
/**
* Utility functions for wp cli commands
*/
abstract class Loco_cli_Utils {
/**
* Collect translation sets according to type/domain filter
* @param string Type of bundle (plugins|themes|core) or a specific Text Domain
* @return Loco_package_Project[]
*/
public static function collectProjects( $filter ){
$projects = array();
$filter = strtolower($filter);
// bundle type filter
if( 'plugins' === $filter ){
$bundles = Loco_package_Plugin::getAll();
$filter = null;
}
else if( 'themes' === $filter ){
$bundles = Loco_package_Theme::getAll();
$filter = null;
}
else if( 'core' === $filter ) {
$bundles = array( Loco_package_Core::create() );
$filter = null;
}
else {
$bundles = array( Loco_package_Core::create() );
$bundles = array_merge( $bundles, Loco_package_Plugin::getAll() );
$bundles = array_merge( $bundles, Loco_package_Theme::getAll() );
}
/* @var Loco_package_Project $project */
foreach( $bundles as $bundle ){
foreach( $bundle as $project ){
if( $filter && strtolower( $project->getDomain() ) !== $filter ){
continue;
}
$projects[] = $project;
}
}
if( ! $projects ){
throw new Loco_error_Exception('No translation sets found');
}
return $projects;
}
/**
* Collect locales from one or more language tags
* @param string zero or more language tags
* @return Loco_Locale[]
*/
public static function collectLocales( $tags ){
$locales = array();
if( '' !== $tags ){
$api = new Loco_api_WordPressTranslations;
foreach( preg_split('/[\\s,;]+/i',$tags,-1,PREG_SPLIT_NO_EMPTY) as $tag ){
$locale = Loco_Locale::parse($tag);
if( ! $locale->isValid() ){
throw new Loco_error_Exception('Invalid locale: '.json_encode($tag) );
}
// TODO could expand language-only tags to known WordPress locales e.g. fr -> fr_FR
$locales[ (string) $locale ] = $locale;
$locale->ensureName($api);
}
// empty locales means ALL locales, so refuse to return ALL when filter was non-empty
if( 0 === count($locales) ){
throw new Loco_error_Exception('No valid locales in: '.json_encode($tags) );
}
}
return $locales;
}
/**
* Simple space-padded table
* @param string[][] data rows to print
*/
public static function tabulate( array $t ){
$w = array();
foreach( $t as $y => $row ){
foreach( $row as $x => $value ){
$width = mb_strlen($value,'UTF-8');
$w[$x] = isset($w[$x]) ? max($w[$x],$width) : $width;
}
}
foreach( $t as $y => $row ){
$line = array();
foreach( $w as $x => $width ){
$value = isset($row[$x]) ? $row[$x] : '';
$value = str_pad($value,$width,' ',STR_PAD_RIGHT);
$line[] = $value;
}
self::debug( implode(' ',$line) );
}
}
/**
* Prints file listing to stdout
*/
public static function tabulateFiles(){
$t = array();
/* @var Loco_fs_File $file */
foreach( func_get_args() as $file ){
if( $file instanceof Loco_fs_File && $file->exists() ){
$f = new Loco_mvc_FileParams(array(),$file);
$t[] = array( $f->owner, $f->group, $f->smode, $f->relpath );
}
}
self::tabulate($t);
}
/**
* WP_CLI debug logger
*/
public static function debug(){
$args = func_get_args();
$message = array_shift($args);
if( $args ){
$message = vsprintf($message,$args);
}
WP_CLI::debug( $message,'loco' );
}
/**
* Parse boolean command line option. Absence is equal to false
*
*/
public static function bool( array $opts, $key ){
$value = isset($opts[$key]) ? $opts[$key] : false;
if( ! is_bool($value) ){
$value = $value && 'false' !== $value & 'no' !== $value;
}
return $value;
}
}
\ No newline at end of file
...@@ -8,8 +8,7 @@ ...@@ -8,8 +8,7 @@
abstract class Loco_compat_MbstringExtension { abstract class Loco_compat_MbstringExtension {
public static function mb_detect_encoding( $str, array $encoding_list = null, $strict = null ){ public static function mb_detect_encoding( $str, array $encoding_list = null, $strict = null ){
// return ! $str || preg_match('/^(?:[\\0-\\x7F]|[\\xC0-\\xDF][\\x80-\\xBF]|[\\xE0-\\xEF][\\x80-\\xBF]{2}|[\\xF0-\\xFF][\\x80-\\xBF]{3})+$/',$str) return ! $str || preg_match('//u',$str)
return ! $str || preg_match('/./u',$str)
? 'UTF-8' ? 'UTF-8'
: 'ISO-8859-1' : 'ISO-8859-1'
; ;
...@@ -20,13 +19,28 @@ abstract class Loco_compat_MbstringExtension { ...@@ -20,13 +19,28 @@ abstract class Loco_compat_MbstringExtension {
} }
public static function mb_strlen( $str, $encoding = null ){ public static function mb_strlen( $str, $encoding = null ){
static $warned = false;
if( ! $warned && preg_match('/[\\x80-\\xFF]/',$str) ){
trigger_error('Character counts will be wrong without mbstring extension',E_USER_WARNING);
$warned = true;
}
return strlen($str); return strlen($str);
} }
public static function mb_convert_encoding( $str, $to_encoding, $from_encoding ){ public static function mb_convert_encoding( $str, $to_encoding, $from_encoding ){
if( $to_encoding !== $from_encoding && '' !== $str ){
// loco_convert_utf8 no longer uses mb_convert_encoding for UTF8->latin1
if( '' === $from_encoding || 'ISO-8859-1' === $from_encoding || 'cp1252' === $from_encoding ){
if( '' === $to_encoding || 'UTF-8' === $to_encoding || 'US-ASCII' === $to_encoding ){
if( function_exists('loco_fix_utf8') ) {
return loco_fix_utf8( $str );
}
}
}
trigger_error('Unable to convert from '.$from_encoding.' to '.$to_encoding.' without mbstring', E_USER_NOTICE );
}
return $str; return $str;
} }
} }
......
...@@ -135,7 +135,7 @@ class Loco_config_BundleWriter implements JsonSerializable { ...@@ -135,7 +135,7 @@ class Loco_config_BundleWriter implements JsonSerializable {
if( $file = $proj->getPot() ){ if( $file = $proj->getPot() ){
$templateElement = $projElement->appendChild( $dom->createElement('template') ); $templateElement = $projElement->appendChild( $dom->createElement('template') );
$templateElement->appendChild( $model->createFileElement($file) ); $templateElement->appendChild( $model->createFileElement($file) );
// template may be prortected from end-user tampering // template may be protected from end-user tampering
if( $proj->isPotLocked() ){ if( $proj->isPotLocked() ){
$templateElement->setAttribute('locked','true'); $templateElement->setAttribute('locked','true');
} }
......
...@@ -36,8 +36,8 @@ class Loco_data_Preferences extends Loco_data_Serializable { ...@@ -36,8 +36,8 @@ class Loco_data_Preferences extends Loco_data_Serializable {
public static function get(){ public static function get(){
$id = get_current_user_id(); $id = get_current_user_id();
if( ! $id ){ if( ! $id ){
// allow null return only in tests, because all real users must be logged in // allow null return only on command line. All web users must be logged in
if( defined('LOCO_TEST') && LOCO_TEST ) { if( 'cli' === PHP_SAPI || defined('LOCO_TEST') ){
return null; return null;
} }
throw new Exception( 'No current user' ); // @codeCoverageIgnore throw new Exception( 'No current user' ); // @codeCoverageIgnore
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* @property string $version Current plugin version installed * @property string $version Current plugin version installed
* @property bool $gen_hash Whether to compile hash table into MO files * @property bool $gen_hash Whether to compile hash table into MO files
* @property bool $use_fuzzy Whether to include Fuzzy strings in MO files * @property bool $use_fuzzy Whether to include Fuzzy strings in MO files
* @property int $fuzziness Fuzzy matching tolerance level, 0-100
* @property int $num_backups Number of backups to keep of Gettext files * @property int $num_backups Number of backups to keep of Gettext files
* @property array $pot_alias Alternative names for POT files in priority order * @property array $pot_alias Alternative names for POT files in priority order
* @property array $php_alias Alternative file extensions for PHP files * @property array $php_alias Alternative file extensions for PHP files
...@@ -42,6 +43,7 @@ class Loco_data_Settings extends Loco_data_Serializable { ...@@ -42,6 +43,7 @@ class Loco_data_Settings extends Loco_data_Serializable {
'version' => '', 'version' => '',
'gen_hash' => false, 'gen_hash' => false,
'use_fuzzy' => true, 'use_fuzzy' => true,
'fuzziness' => 20,
'num_backups' => 1, 'num_backups' => 1,
'pot_alias' => array( 'default.po', 'en_US.po', 'en.po' ), 'pot_alias' => array( 'default.po', 'en_US.po', 'en.po' ),
'php_alias' => array( 'php', 'twig' ), 'php_alias' => array( 'php', 'twig' ),
......
...@@ -34,6 +34,16 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -34,6 +34,16 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
*/ */
public static function add( Loco_error_Exception $error ){ public static function add( Loco_error_Exception $error ){
$notices = self::get(); $notices = self::get();
// if exception wasn't thrown we have to do some work to establish where it was invoked
if( __FILE__ === $error->getFile() ){
$error->setCallee(1);
}
// write error immediately under WP_CLIT
if( 'cli' === PHP_SAPI && class_exists('WP_CLI',false) ){
$error->logCli();
return $error;
}
// else buffer notices for displaying when UI is ready
$notices->errors[] = $error; $notices->errors[] = $error;
// do late flush if we missed the boat // do late flush if we missed the boat
if( did_action('loco_admin_init') ){ if( did_action('loco_admin_init') ){
...@@ -42,10 +52,6 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -42,10 +52,6 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
if( did_action('admin_notices') ){ if( did_action('admin_notices') ){
$notices->on_admin_notices(); $notices->on_admin_notices();
} }
// if exception wasn't thrown we have to do some work to establish where it was invoked
if( __FILE__ === $error->getFile() ){
$error->setCallee(1);
}
// Log messages of minimum priority and up, depending on debug mode // Log messages of minimum priority and up, depending on debug mode
// note that non-debug level is in line with error_reporting set by WordPress (notices ignored) // note that non-debug level is in line with error_reporting set by WordPress (notices ignored)
$priority = loco_debugging() ? Loco_error_Exception::LEVEL_DEBUG : Loco_error_Exception::LEVEL_WARNING; $priority = loco_debugging() ? Loco_error_Exception::LEVEL_DEBUG : Loco_error_Exception::LEVEL_WARNING;
...@@ -118,7 +124,8 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -118,7 +124,8 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
* @return Loco_error_Exception[] * @return Loco_error_Exception[]
*/ */
public static function destroy(){ public static function destroy(){
if( $notices = self::$singleton ){ $notices = self::$singleton;
if( $notices instanceof Loco_error_AdminNotices ){
$buffer = $notices->errors; $buffer = $notices->errors;
$notices->errors = array(); $notices->errors = array();
self::$singleton = null; self::$singleton = null;
...@@ -145,7 +152,7 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -145,7 +152,7 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
/** /**
* @return void * @return void
*/ */
private function flush(){ private function flushHtml(){
if( $this->errors ){ if( $this->errors ){
$htmls = array(); $htmls = array();
foreach( $this->errors as $error ){ foreach( $this->errors as $error ){
...@@ -169,13 +176,24 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -169,13 +176,24 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
} }
} }
/**
* @return void
*/
private function flushCli(){
foreach( $this->errors as $e ){
$e->logCli();
}
$this->errors = array();
}
/** /**
* admin_notices action handler. * admin_notices action handler.
*/ */
public function on_admin_notices(){ public function on_admin_notices(){
if( ! $this->inline ){ if( ! $this->inline ){
$this->flush(); $this->flushHtml();
} }
} }
...@@ -186,7 +204,7 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -186,7 +204,7 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
*/ */
public function on_loco_admin_notices(){ public function on_loco_admin_notices(){
$this->inline = true; $this->inline = true;
$this->flush(); $this->flushHtml();
} }
...@@ -205,8 +223,11 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable { ...@@ -205,8 +223,11 @@ class Loco_error_AdminNotices extends Loco_hooks_Hookable {
*/ */
public function __destruct(){ public function __destruct(){
$this->inline = false; $this->inline = false;
if( ! loco_doing_ajax() ){ if( class_exists('WP_CLI',false) ){
$this->flush(); $this->flushCli();
}
else if( ! loco_doing_ajax() ){
$this->flushHtml();
} }
} }
......
...@@ -26,6 +26,14 @@ class Loco_error_Debug extends Loco_error_Exception { ...@@ -26,6 +26,14 @@ class Loco_error_Debug extends Loco_error_Exception {
public function getLevel(){ public function getLevel(){
return Loco_error_Exception::LEVEL_DEBUG; return Loco_error_Exception::LEVEL_DEBUG;
} }
/**
* {@inheritDoc}
*/
public function logCli(){
WP_CLI::debug( $this->getMessage(), 'loco' );
}
/** /**
......
...@@ -103,7 +103,7 @@ class Loco_error_Exception extends Exception implements JsonSerializable { ...@@ -103,7 +103,7 @@ class Loco_error_Exception extends Exception implements JsonSerializable {
$path = $file->getRelativePath( loco_plugin_root() ); $path = $file->getRelativePath( loco_plugin_root() );
$text = sprintf('[Loco.%s] "%s" in %s:%u', $this->getType(), $this->getMessage(), $path, $this->getRealLine() ); $text = sprintf('[Loco.%s] "%s" in %s:%u', $this->getType(), $this->getMessage(), $path, $this->getRealLine() );
// separate error log in CWD for tests // separate error log in CWD for tests
if( 'cli' === PHP_SAPI && defined('LOCO_TEST') && LOCO_TEST ){ if( defined('LOCO_TEST') && LOCO_TEST ){
error_log( '['.date('c').'] '.$text."\n", 3, 'debug.log' ); error_log( '['.date('c').'] '.$text."\n", 3, 'debug.log' );
} }
// Else write to default PHP log, but note that WordPress may have set this to wp-content/debug.log. // Else write to default PHP log, but note that WordPress may have set this to wp-content/debug.log.
...@@ -141,6 +141,15 @@ class Loco_error_Exception extends Exception implements JsonSerializable { ...@@ -141,6 +141,15 @@ class Loco_error_Exception extends Exception implements JsonSerializable {
} }
/**
* Call wp cli logging function
* @return void
*/
public function logCli(){
WP_CLI::error( $this->getMessage(), false );
}
/** /**
* Get localized notice level name * Get localized notice level name
* @return string * @return string
......
...@@ -28,4 +28,12 @@ class Loco_error_Notice extends Loco_error_Exception { ...@@ -28,4 +28,12 @@ class Loco_error_Notice extends Loco_error_Exception {
return Loco_error_Exception::LEVEL_NOLOG; return Loco_error_Exception::LEVEL_NOLOG;
} }
/**
* {@inheritDoc}
*/
public function logCli(){
WP_CLI::log( $this->getMessage() );
}
} }
\ No newline at end of file
<?php <?php
/** /**
* * Exception thrown when parsing fails
*/ */
class Loco_error_ParseException extends Loco_error_Exception { class Loco_error_ParseException extends Loco_error_Exception {
/** /**
* @var string * @var string[]
*/ */
private $context; private $context;
...@@ -16,32 +16,36 @@ class Loco_error_ParseException extends Loco_error_Exception { ...@@ -16,32 +16,36 @@ class Loco_error_ParseException extends Loco_error_Exception {
* @return self * @return self
*/ */
public function setContext( $line, $column, $source ){ public function setContext( $line, $column, $source ){
$this->context = null; $this->context = array();
// If line given as 0 then treat column as offset in an unknown number of lines $lines = preg_split( '/\\r?\\n/', $source, $line+1 );
if( 0 === $line ){ $offset = $line - 1;
$lines = preg_split( '/\\r?\\n/', substr($source,0,$column)); if( isset($lines[$offset]) ){
$line = count($lines); $this->context[] = $lines[$offset];
$column = strlen( end($lines) ); $this->context[] = str_repeat(' ', max(0,$column-1) ).'^';
} }
// get line of source code where error is and construct a ____^ thingy to show error on next line
// this requires that full source is passed in, so line number must be real
if( loco_debugging() ){
$lines = preg_split( '/\\r?\\n/', $source, $line+1 );
$offset = $line - 1;
if( isset($lines[$offset]) ){
$this->context = $lines[$offset] ."\n". str_repeat(' ', max(0,$column) ).'^';
}
}
// wrap initial message with context data
$this->message = sprintf("Error at line %u, column %u: %s", $line, $column, $this->message ); $this->message = sprintf("Error at line %u, column %u: %s", $line, $column, $this->message );
return $this; return $this;
} }
/**
* @param int zero-based offset to failure point
* @param string source in which to identify line and column
* @return self
*/
public function setOffsetContext( $offset, $source ){
$lines = preg_split( '/\\r?\\n/', substr($source,0,$offset) );
$line = count($lines);
$column = 1 + strlen( end($lines) );
return $this->setContext( $line, $column, $source );
}
/** /**
* @return string * @return string
*/ */
public function getContext(){ public function getContext(){
return $this->context; return is_array($this->context) ? implode("\n",$this->context) : '';
} }
} }
...@@ -27,4 +27,13 @@ class Loco_error_Success extends Loco_error_Exception { ...@@ -27,4 +27,13 @@ class Loco_error_Success extends Loco_error_Exception {
return Loco_error_Exception::LEVEL_NOLOG; return Loco_error_Exception::LEVEL_NOLOG;
} }
/**
* {@inheritDoc}
*/
public function logCli(){
WP_CLI::success( $this->getMessage() );
}
} }
...@@ -27,4 +27,12 @@ class Loco_error_Warning extends Loco_error_Exception { ...@@ -27,4 +27,12 @@ class Loco_error_Warning extends Loco_error_Exception {
return Loco_error_Exception::LEVEL_WARNING; return Loco_error_Exception::LEVEL_WARNING;
} }
/**
* {@inheritDoc}
*/
public function logCli(){
WP_CLI::warning( $this->getMessage() );
}
} }
\ No newline at end of file
...@@ -170,7 +170,7 @@ class Loco_fs_File { ...@@ -170,7 +170,7 @@ class Loco_fs_File {
if( $writer->isDirect() && ( $uid = Loco_compat_PosixExtension::getuid() ) ){ if( $writer->isDirect() && ( $uid = Loco_compat_PosixExtension::getuid() ) ){
return $uid === $this->uid() || $uid === $parent->uid(); return $uid === $this->uid() || $uid === $parent->uid();
} }
// else delete operation won't be done directly, so can't pre-empt sticky problems // else delete operation won't be done directly, so can't preempt sticky problems
// TODO is it worth comparing FTP username etc.. for ownership? // TODO is it worth comparing FTP username etc.. for ownership?
} }
// defaulting to "deletable" based on fact that parent is writable. // defaulting to "deletable" based on fact that parent is writable.
...@@ -199,7 +199,7 @@ class Loco_fs_File { ...@@ -199,7 +199,7 @@ class Loco_fs_File {
/** /**
* Check if file can't be overwitten when existent, nor created when non-existent * Check if file can't be overwritten when existent, nor created when non-existent
* This does not check permissions recursively as directory trees are not built implicitly * This does not check permissions recursively as directory trees are not built implicitly
* @return bool * @return bool
*/ */
......
...@@ -13,6 +13,7 @@ class Loco_fs_FileMode { ...@@ -13,6 +13,7 @@ class Loco_fs_FileMode {
/** /**
* Instantiate from integer file mode * Instantiate from integer file mode
* @param int
*/ */
public function __construct( $mode ){ public function __construct( $mode ){
$this->i = (int) $mode; $this->i = (int) $mode;
......
...@@ -41,7 +41,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { ...@@ -41,7 +41,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
} }
catch( Loco_error_ParseException $e ){ catch( Loco_error_ParseException $e ){
$path = $file->getRelativePath( loco_constant('WP_CONTENT_DIR') ); $path = $file->getRelativePath( loco_constant('WP_CONTENT_DIR') );
Loco_error_AdminNotices::debug( sprintf('Failed to parse %s as a %s file',$path,$type) ); Loco_error_AdminNotices::debug( sprintf('Failed to parse %s as a %s file; %s',$path,$type,$e->getMessage()) );
throw new Loco_error_ParseException( sprintf('Invalid %s file: %s',$type,basename($path)) ); throw new Loco_error_ParseException( sprintf('Invalid %s file: %s',$type,basename($path)) );
} }
} }
...@@ -98,7 +98,6 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { ...@@ -98,7 +98,6 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
* @return string * @return string
*/ */
public static function ensureUtf8( $src ){ public static function ensureUtf8( $src ){
loco_check_extension('mbstring');
$src = loco_remove_bom($src,$cs); $src = loco_remove_bom($src,$cs);
if( ! $cs ){ if( ! $cs ){
// read PO header, requiring partial parse // read PO header, requiring partial parse
...@@ -108,15 +107,8 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { ...@@ -108,15 +107,8 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
catch( Loco_error_ParseException $e ){ catch( Loco_error_ParseException $e ){
Loco_error_AdminNotices::debug( $e->getMessage() ); Loco_error_AdminNotices::debug( $e->getMessage() );
} }
// fall back on detection which will only work for latin1
if( ! $cs ){
$cs = mb_detect_encoding($src,array('UTF-8','ISO-8859-1'),true);
}
}
if( $cs && 'UTF-8' !== $cs ){
$src = mb_convert_encoding($src,'UTF-8',array($cs) );
} }
return $src; return loco_convert_utf8($src,$cs,false);
} }
...@@ -176,7 +168,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { ...@@ -176,7 +168,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
* @param string text domain for JED metadata * @param string text domain for JED metadata
* @param LocoPoMessage[] pre-compiled messages * @param LocoPoMessage[] pre-compiled messages
* @return string * @return string
*/ *
public function jedize( $domain, array $po ){ public function jedize( $domain, array $po ){
$head = $this->getHeaders(); $head = $this->getHeaders();
// start locale_data with JED header // start locale_data with JED header
...@@ -185,7 +177,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { ...@@ -185,7 +177,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
'lang' => $head['language'], 'lang' => $head['language'],
'plural-forms' => $head['plural-forms'], 'plural-forms' => $head['plural-forms'],
) ); ) );
/* @var LocoPoMessage $msg */ // @var LocoPoMessage $msg
foreach( $po as $msg ){ foreach( $po as $msg ){
$data[ $msg->getKey() ] = $msg->getMsgstrs(); $data[ $msg->getKey() ] = $msg->getMsgstrs();
} }
...@@ -202,7 +194,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { ...@@ -202,7 +194,7 @@ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable {
$domain => $data, $domain => $data,
), ),
), $json_options ); ), $json_options );
} }*/
/** /**
......
...@@ -25,7 +25,7 @@ class Loco_gettext_Extraction { ...@@ -25,7 +25,7 @@ class Loco_gettext_Extraction {
/** /**
* List of files skipped due to memory limit * List of files skipped due to memory limit
* @var Loco_fs_FileList * @var Loco_fs_FileList|null
*/ */
private $skipped; private $skipped;
...@@ -42,7 +42,6 @@ class Loco_gettext_Extraction { ...@@ -42,7 +42,6 @@ class Loco_gettext_Extraction {
*/ */
public function __construct( Loco_package_Bundle $bundle ){ public function __construct( Loco_package_Bundle $bundle ){
loco_check_extension('ctype'); loco_check_extension('ctype');
loco_check_extension('mbstring');
if( ! loco_check_extension('tokenizer') ){ if( ! loco_check_extension('tokenizer') ){
throw new Loco_error_Exception('String extraction not available without required extension'); throw new Loco_error_Exception('String extraction not available without required extension');
} }
...@@ -50,8 +49,9 @@ class Loco_gettext_Extraction { ...@@ -50,8 +49,9 @@ class Loco_gettext_Extraction {
$this->extracted = new LocoExtracted; $this->extracted = new LocoExtracted;
$this->extracted->setDomain('default'); $this->extracted->setDomain('default');
$this->extras = array(); $this->extras = array();
if( $default = $bundle->getDefaultProject() ){ $default = $bundle->getDefaultProject();
$domain = (string) $default->getDomain(); if( $default instanceof Loco_package_Project ){
$domain = $default->getDomain()->getName();
// wildcard stands in for empty text domain, meaning unspecified or dynamic domains will be included. // wildcard stands in for empty text domain, meaning unspecified or dynamic domains will be included.
// note that strings intended to be in "default" domain must specify explicitly, or be included here too. // note that strings intended to be in "default" domain must specify explicitly, or be included here too.
if( '*' === $domain ){ if( '*' === $domain ){
......
...@@ -40,9 +40,8 @@ abstract class Loco_mvc_AdminController extends Loco_mvc_Controller { ...@@ -40,9 +40,8 @@ abstract class Loco_mvc_AdminController extends Loco_mvc_Controller {
$this->auth(); $this->auth();
// check essential extensions on all pages so admin notices are shown // check essential extensions on all pages so admin notices are shown
foreach( array('json','mbstring') as $ext ){ loco_check_extension('json');
loco_check_extension($ext); loco_check_extension('mbstring');
}
// add contextual help tabs to current screen if there are any // add contextual help tabs to current screen if there are any
if( $screen = get_current_screen() ){ if( $screen = get_current_screen() ){
......
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
* @property-read string $name * @property-read string $name
* @property-read string $path * @property-read string $path
* @property-read string $relpath * @property-read string $relpath
* @property-read string $size
* @property-read int $imode
* @property-read string $smode
* @property-read string $group
* @property-read string $owner
*/ */
class Loco_mvc_FileParams extends Loco_mvc_ViewParams { class Loco_mvc_FileParams extends Loco_mvc_ViewParams {
...@@ -129,7 +134,6 @@ class Loco_mvc_FileParams extends Loco_mvc_ViewParams { ...@@ -129,7 +134,6 @@ class Loco_mvc_FileParams extends Loco_mvc_ViewParams {
/** /**
* Using slightly modified version of WordPress's Human time differencing * Using slightly modified version of WordPress's Human time differencing
* + Added "Just now" when in the last 30 seconds * + Added "Just now" when in the last 30 seconds
* TODO possibly replace with custom function that includes "Yesterday" etc..
* @internal * @internal
* @return string * @return string
*/ */
......
...@@ -24,6 +24,8 @@ class Loco_output_DiffRenderer extends WP_Text_Diff_Renderer_Table { ...@@ -24,6 +24,8 @@ class Loco_output_DiffRenderer extends WP_Text_Diff_Renderer_Table {
/** /**
* Render diff of two files, presumed to be PO or POT * Render diff of two files, presumed to be PO or POT
* @param Loco_fs_File Left hand file
* @param Loco_fs_File Right hand file
* @return string HTML table * @return string HTML table
*/ */
public function renderFiles( Loco_fs_File $lhs, Loco_fs_File $rhs ){ public function renderFiles( Loco_fs_File $lhs, Loco_fs_File $rhs ){
...@@ -34,10 +36,23 @@ class Loco_output_DiffRenderer extends WP_Text_Diff_Renderer_Table { ...@@ -34,10 +36,23 @@ class Loco_output_DiffRenderer extends WP_Text_Diff_Renderer_Table {
} }
// like wp_text_diff but avoiding whitespace normalization // like wp_text_diff but avoiding whitespace normalization
// uses deprecated signature for 'auto' in case of old WordPress // uses deprecated signature for 'auto' in case of old WordPress
return $this->render( new Text_Diff ( return $this->render( new Text_Diff( self::splitFile($lhs), self::splitFile($rhs) ) );
preg_split( '/(?:\\n|\\r\\n?)/', Loco_gettext_Data::ensureUtf8( $lhs->getContents() ) ), }
preg_split( '/(?:\\n|\\r\\n?)/', Loco_gettext_Data::ensureUtf8( $rhs->getContents() ) )
) );
/**
* @param Loco_fs_File
* @return string[]
*/
private static function splitFile( Loco_fs_File $file ){
$src = $file->getContents();
$src = Loco_gettext_Data::ensureUtf8($src);
$arr = preg_split( '/\\r?\\n/', $src );
if( ! is_array($arr) ){
$f = new Loco_mvc_FileParams( array(), $file );
throw new Loco_error_Exception('Failed to split '.$f->relpath.' ('.$f->size.')' );
}
return $arr;
} }
......
...@@ -23,6 +23,7 @@ class Loco_package_Locale { ...@@ -23,6 +23,7 @@ class Loco_package_Locale {
/** /**
* Construct with locale to filter on * Construct with locale to filter on
* @param Loco_Locale|null
*/ */
public function __construct( Loco_locale $locale = null ){ public function __construct( Loco_locale $locale = null ){
$this->index = new ArrayObject; $this->index = new ArrayObject;
...@@ -34,7 +35,8 @@ class Loco_package_Locale { ...@@ -34,7 +35,8 @@ class Loco_package_Locale {
/** /**
* Add another locale to serarch on * Add another locale to search on
* @param Loco_Locale
* @return Loco_package_Locale * @return Loco_package_Locale
*/ */
public function addLocale( Loco_Locale $locale ){ public function addLocale( Loco_Locale $locale ){
...@@ -47,50 +49,33 @@ class Loco_package_Locale { ...@@ -47,50 +49,33 @@ class Loco_package_Locale {
/** /**
* @return Loco_package_Project * @param Loco_fs_File
* @return Loco_package_Project|null
*/ */
public function getProject( Loco_fs_File $file ){ public function getProject( Loco_fs_File $file ){
$path = $file->getPath(); $path = $file->getPath();
if( isset($this->index[$path]) ){ if( isset($this->index[$path]) ){
return $this->index[$path]; return $this->index[$path];
} }
return null;
} }
/** /**
* @return array * @return Loco_package_Bundle[]
*/ */
public function getBundles(){ public function getBundles(){
$bundles = $this->bundles; $bundles = $this->bundles;
if( ! $bundles ){ if( ! $bundles ){
$bundles = array ( $bundles = array( Loco_package_Core::create() );
Loco_package_Core::create() $bundles = array_merge( $bundles, Loco_package_Plugin::getAll() );
); $bundles = array_merge( $bundles, Loco_package_Theme::getAll() );
foreach( Loco_package_Plugin::get_plugins() as $handle => $data ){
try {
$bundles[] = Loco_package_Plugin::create( $handle );
}
catch( Exception $e ){
// @codeCoverageIgnore
}
}
/* @var $theme WP_Theme */
foreach( wp_get_themes() as $theme ){
try {
$bundles[] = Loco_package_Theme::create( $theme->get_stylesheet() );
}
catch( Exception $e ){
// @codeCoverageIgnore
}
}
$this->bundles = $bundles; $this->bundles = $bundles;
} }
return $bundles; return $bundles;
} }
/** /**
* @return loco_fs_FileList * @return loco_fs_FileList
*/ */
...@@ -98,9 +83,8 @@ class Loco_package_Locale { ...@@ -98,9 +83,8 @@ class Loco_package_Locale {
$index = $this->index; $index = $this->index;
$suffixes = $this->match; $suffixes = $this->match;
$list = new Loco_fs_FileList; $list = new Loco_fs_FileList;
/* @var $bundle Loco_package_Bundle */
foreach( $this->getBundles() as $bundle ){ foreach( $this->getBundles() as $bundle ){
/* @var $project Loco_package_Project */ /* @var Loco_package_Project $project */
foreach( $bundle as $project ){ foreach( $bundle as $project ){
/* @var $file Loco_fs_File */ /* @var $file Loco_fs_File */
foreach( $project->findLocaleFiles('po') as $file ){ foreach( $project->findLocaleFiles('po') as $file ){
...@@ -119,14 +103,12 @@ class Loco_package_Locale { ...@@ -119,14 +103,12 @@ class Loco_package_Locale {
} }
/** /**
* @return loco_fs_FileList * @return loco_fs_FileList
*/ */
public function findTemplateFiles(){ public function findTemplateFiles(){
$index = $this->index; $index = $this->index;
$list = new Loco_fs_FileList; $list = new Loco_fs_FileList;
/* @var $bundle Loco_package_Bundle */
foreach( $this->getBundles() as $bundle ){ foreach( $this->getBundles() as $bundle ){
/* @var $project Loco_package_Project */ /* @var $project Loco_package_Project */
foreach( $bundle as $project ){ foreach( $bundle as $project ){
...@@ -140,6 +122,5 @@ class Loco_package_Locale { ...@@ -140,6 +122,5 @@ class Loco_package_Locale {
} }
return $list; return $list;
} }
} }
...@@ -43,9 +43,26 @@ class Loco_package_Plugin extends Loco_package_Bundle { ...@@ -43,9 +43,26 @@ class Loco_package_Plugin extends Loco_package_Bundle {
} }
/**
* @return Loco_package_Plugin[]
*/
public static function getAll(){
$plugins = array();
foreach( self::get_plugins() as $handle => $data ){
try {
$plugins[] = Loco_package_Plugin::create($handle);
}
catch( Exception $e ){
// @codeCoverageIgnore
}
}
return $plugins;
}
/** /**
* Maintaining our own cache of full paths to available plugins, because get_mu_plugins doesn't get cached by WP * Maintaining our own cache of full paths to available plugins, because get_mu_plugins doesn't get cached by WP
* @return array * @return array[]
*/ */
public static function get_plugins(){ public static function get_plugins(){
$cached = wp_cache_get('plugins','loco'); $cached = wp_cache_get('plugins','loco');
......
...@@ -355,6 +355,35 @@ class Loco_package_Project { ...@@ -355,6 +355,35 @@ class Loco_package_Project {
} }
/**
* Get first valid domain path
* @param bool whether directory should exist
* @return Loco_fs_Directory
*/
private function getSafeDomainPath(){
// use first configured domain path that exists
foreach( $this->getConfiguredTargets() as $d ){
if( $d->exists() ){
return $d;
}
}
// fallback to unconfigured, but possibly existent folders
$base = $this->getBundle()->getDirectoryPath();
foreach( array('languages','language','lang','l10n','i18n') as $d ){
$d = new Loco_fs_Directory($d);
$d->normalize($base);
if( $this->isTargetExcluded($d) ){
continue;
}
if( $d->exists() ){
return $d;
}
}
// Give up and place in root
return new Loco_fs_Directory($base);
}
/** /**
* Lazy create all searchable source paths * Lazy create all searchable source paths
* @return Loco_fs_FileFinder * @return Loco_fs_FileFinder
...@@ -523,9 +552,10 @@ class Loco_package_Project { ...@@ -523,9 +552,10 @@ class Loco_package_Project {
*/ */
public function getPot(){ public function getPot(){
if( ! $this->pot ){ if( ! $this->pot ){
$name = $this->getSlug().'.pot'; $slug = $this->getSlug();
$name = ( $slug ? $slug : $this->getDomain()->getName() ).'.pot';
if( '.pot' !== $name ){ if( '.pot' !== $name ){
// find under configured domain paths // find actual file under configured domain paths
$targets = $this->getConfiguredTargets()->copy(); $targets = $this->getConfiguredTargets()->copy();
// always permit POT file in the bundle root (i.e. outside domain path) // always permit POT file in the bundle root (i.e. outside domain path)
if( $this->isDomainDefault() && $this->bundle->hasDirectoryPath() ){ if( $this->isDomainDefault() && $this->bundle->hasDirectoryPath() ){
...@@ -551,11 +581,16 @@ class Loco_package_Project { ...@@ -551,11 +581,16 @@ class Loco_package_Project {
} }
} }
} }
// fall back to a directory that exists, but where the POT may not
if( ! $this->pot ){
$this->pot = new Loco_fs_File($name);
$this->pot->normalize( (string) $this->getSafeDomainPath() );
}
} }
return $this->pot; return $this->pot;
} }
/** /**
* Force the use of a known POT file. This could be a PO file if necessary * Force the use of a known POT file. This could be a PO file if necessary
* @param Loco_fs_File template POT file * @param Loco_fs_File template POT file
......
<?php <?php
/** /**
* Object represents a Text Domain within a bundle. * Object represents a Text Domain within a bundle.
* TODO implement a conflict watcher to warn when domains are shared by multiple bundles?
*/ */
class Loco_package_TextDomain extends ArrayIterator { class Loco_package_TextDomain extends ArrayIterator {
/** /**
* Actual Gettext-like name of Text Domain, e.g. "twentyfifteen" * Actual Gettext-like name of Text Domain, e.g. "twentyfifteen"
* @var string * @var string
*/ */
private $name; private $name;
/** /**
* Whether this is the officially declared domain for a theme or plugin * Whether this is the officially declared domain for a theme or plugin
* @var bool * @var bool
*/ */
private $canonical = false; private $canonical = false;
/** /**
* Create new Text Domain from its name * Create new Text Domain from its name
* @param string
*/ */
public function __construct( $name ){ public function __construct( $name ){
parent::__construct();
$this->name = $name; $this->name = $name;
} }
/** /**
* @internal * @internal
*/ */
...@@ -45,6 +46,8 @@ class Loco_package_TextDomain extends ArrayIterator { ...@@ -45,6 +46,8 @@ class Loco_package_TextDomain extends ArrayIterator {
/** /**
* Create a named project in a given bundle for this Text Domain * Create a named project in a given bundle for this Text Domain
* @param Loco_package_Bundle bundle of which this is one set of translations
* @param string
* @return Loco_package_Project * @return Loco_package_Project
*/ */
public function createProject( Loco_package_Bundle $bundle, $name ){ public function createProject( Loco_package_Bundle $bundle, $name ){
...@@ -56,6 +59,7 @@ class Loco_package_TextDomain extends ArrayIterator { ...@@ -56,6 +59,7 @@ class Loco_package_TextDomain extends ArrayIterator {
/** /**
* @param bool
* @return Loco_package_TextDomain * @return Loco_package_TextDomain
*/ */
public function setCanonical( $bool ){ public function setCanonical( $bool ){
...@@ -70,5 +74,5 @@ class Loco_package_TextDomain extends ArrayIterator { ...@@ -70,5 +74,5 @@ class Loco_package_TextDomain extends ArrayIterator {
public function isCanonical(){ public function isCanonical(){
return $this->canonical; return $this->canonical;
} }
} }
...@@ -71,6 +71,23 @@ class Loco_package_Theme extends Loco_package_Bundle { ...@@ -71,6 +71,23 @@ class Loco_package_Theme extends Loco_package_Bundle {
} }
/**
* @return Loco_package_Theme[]
*/
public static function getAll(){
$themes = array();
foreach( wp_get_themes(array('errors'=>null)) as $theme ){
try {
$themes[] = self::createFromTheme($theme);
}
catch( Exception $e ){
// @codeCoverageIgnore
}
}
return $themes;
}
/** /**
* Create theme bundle definition from WordPress theme handle * Create theme bundle definition from WordPress theme handle
* *
......
...@@ -98,6 +98,23 @@ $fs_help = apply_filters('loco_external','https://localise.biz/wordpress/plugin/ ...@@ -98,6 +98,23 @@ $fs_help = apply_filters('loco_external','https://localise.biz/wordpress/plugin/
</fieldset> </fieldset>
</td> </td>
</tr> </tr>
<tr>
<th scope="row"><?php esc_html_e('Syncing PO files','loco-translate')?></th>
<td>
<fieldset>
<legend class="screen-reader-text">
<span><?php esc_html_e('Syncing PO files','loco-translate')?></span>
</legend>
<p>
<label for="loco--">
<?php esc_html_e('Fuzzy matching tolerance:','loco-translate')?>
</label>
<input type="text" size="5" maxlength="3" name="opts[fuzziness]" id="loco--fuzziness" value="<?php echo esc_attr( $opts->fuzziness)?>" placeholder="0-100" />
<span>%</span>
</p>
</fieldset>
</td>
</tr>
<!--tr> <!--tr>
<th scope="row"><?php esc_html_e('POT template files','loco-translate')?></th> <th scope="row"><?php esc_html_e('POT template files','loco-translate')?></th>
<td> <td>
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.l-aside--position--wide { .l-aside--position--wide {
@media (--min--medium) { @media (--min--medium) {
flex: 0 0 470px; padding: 70px 55px; max-width: 470px; flex: 1 1 280px; padding: 70px 55px; max-width: 470px;
} }
} }
......
...@@ -8,6 +8,15 @@ ...@@ -8,6 +8,15 @@
} }
} }
.l-content--position-banner {
max-width: 1096px;
margin: 10px auto 20px;
@media (--min--medium) {
margin: -20px auto 20px;
}
}
.l-content--position { position: relative; padding: 10px 10px 0; .l-content--position { position: relative; padding: 10px 10px 0;
@media (--min--medium) { @media (--min--medium) {
padding: 40px 20px; padding: 40px 20px;
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
/* critical:start */ /* critical:start */
/*.l-main { flex: 1 1 100%; }*/ /*.l-main { flex: 1 1 100%; }*/
.l-main { flex: 1 1 auto; } .l-main { flex: 1 1 400px; }
.l-main--content { background-color: #FFFFFF; padding: 30px 20px; .l-main--content { background-color: #fff; padding: 30px 20px;
img { max-width: 100%; height: auto; } img { max-width: 100%; height: auto; }
@media (--min--medium) { @media (--min--medium) {
padding: 40px 50px; padding: 40px 50px;
......
...@@ -42,3 +42,8 @@ ...@@ -42,3 +42,8 @@
padding-bottom: 40px; padding-bottom: 40px;
} }
} }
.c-job-facebook--wide {
max-width: 340px;
min-height: 190px;
}
...@@ -15,6 +15,11 @@ ...@@ -15,6 +15,11 @@
} }
} }
.c-recommend-top {
display: flex;
min-height: 62px;
}
.c-recommend--headline { display: block; color: #fff; max-width: 180px; margin-bottom: 20px; font-size: 21px; font-weight: 500; } .c-recommend--headline { display: block; color: #fff; max-width: 180px; margin-bottom: 20px; font-size: 21px; font-weight: 500; }
.c-recommend--anchor { color: #fff; font-size: 15px; } .c-recommend--anchor { color: #fff; font-size: 15px; }
...@@ -38,6 +43,7 @@ ...@@ -38,6 +43,7 @@
background-position: 0 0; background-position: 0 0;
background-size: cover; background-size: cover;
transform: rotate(-20deg); transform: rotate(-20deg);
background-repeat: no-repeat;
} }
strong { strong {
...@@ -60,10 +66,57 @@ ...@@ -60,10 +66,57 @@
.c-recommend { .c-recommend {
&::before { background-image: url(/wp-content/themes/biuro/i/recommend.png); } &::before { background-image: url(/wp-content/themes/biuro/i/recommend.png); }
} }
.c-recommend-top {
&::before { background-image: url(/wp-content/themes/biuro/i/recommend-top.png); }
}
} }
.js.webp { .js.webp {
.c-recommend { .c-recommend {
&::before { background-image: url(/wp-content/themes/biuro/i/recommend.webp); } &::before { background-image: url(/wp-content/themes/biuro/i/recommend.webp); }
} }
.c-recommend-top {
&::before { background-image: url(/wp-content/themes/biuro/i/recommend-top.webp); }
}
}
.c-recommend-top {
background: radial-gradient(44.04% 180.85% at 56.55% 59.57%, rgba(87, 181, 181, 0.54) 0%, rgba(90, 204, 204, 0.54) 0.01%, #34B9BA 100%);
align-items: center;
&:before {
transform: rotate(0);
top: auto;
right: 35px;
bottom: 0;
left: auto;
width: 130px;
height: 51px;
@media (--min--medium) {
width: 228px;
height: 89px;
}
}
.c-recommend--headline {
flex: 1 1 50%;
max-width: 100%;
margin: 0;
padding-right: 20px;
font-size: 14px;
line-height: 20px;
@media (--min--medium) {
font-size: 18px;
line-height: 34px;
}
}
.c-recommend--anchor {
flex: 0 0 auto;
margin: 0 0 20px;
@media (--min--medium) {
margin: 0 240px 0 0;
}
}
} }
:root{--color--gray:#7e8683;--color--gray-darker:#2a3644;--color--green:#1fb299;--color--green-darker:#149a83;--color--green-dark:#006957;--color--blue-dark:#1d2a3a;--color--gray-light:#f8f8f8;--typo--font-family:-apple-system,BlinkMacSystemFont,"Segoe UI Light","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;--typo--font-size:1.5rem;--typo--weight-regular:400;--typo--weight-bold:700;--typo--line-height:1.2;--typo--font-face:"Roboto",sans-serif;--layout-width:1210px;--layout-width--small:870px;--layout-width--large:1150px}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}a{color:inherit}body{font-size:14px;line-height:19px;color:#2a3644;color:var(--color--gray-darker);font-family:Roboto,sans-serif;font-family:var(--typo--font-face);background:#f8f8f8;display:flex;flex-direction:column;min-height:100vh;padding-top:70px}h1{font-size:22px;line-height:29px;margin:0 0 22px}h1,h2{color:#2a3644;font-weight:500}h2{font-size:19px;line-height:25px;margin:0 0 19px}h3{color:#2a3644;font-weight:500;font-size:16px;line-height:20px;margin:0 0 16px}html{min-height:100%;font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}table{border-collapse:collapse;border-spacing:0}.l-body--langing{padding-top:0!important}.l-body--langing .u-fill--logo{fill:#fff!important}.l-inner{max-width:1210px;max-width:var(--layout-width);padding-right:20px;padding-left:20px}.l-inner,.l-inner-jobs{margin-right:auto;margin-left:auto}.l-inner-jobs{max-width:990px;padding-right:10px;padding-left:10px}.c-jobs--inner,.c-services,.c-trust--inner,.c-values--inner,.l-inner-small{max-width:870px;max-width:var(--layout-width--small);margin-right:auto;margin-left:auto;padding-right:20px;padding-left:20px}.l-inner--header{display:flex;flex-direction:row;align-items:center}.l-inner--header-motherson{max-width:1030px}.l-header{position:fixed;background:#fff}.l-header,.l-header--langing{top:0;left:0;width:100%;z-index:300;height:70px}.l-header--langing{position:absolute}.l-content{max-width:1150px;max-width:var(--layout-width--large);padding-right:20px;padding-left:20px;margin:0 auto}.l-content--position-banner{max-width:1096px;margin:10px auto 20px}.l-content--position{position:relative;padding:10px 10px 0}.l-content--position:before{content:"";position:absolute;top:0;left:0;height:244px;width:100%;background:linear-gradient(358.45deg,#3c7e9e,#1fb299)}.l-content--position-inner{position:relative;max-width:970px;margin:0 auto;border-radius:3px;background-color:#fff;box-shadow:0 1px 31px -23px #6a7481}.l-content--position-inner .l-main{padding:20px}.l-content--position-inner--wide{max-width:1100px}.l-content--heading{display:block;padding-top:10px;padding-bottom:15px}.l-content--heading h1{margin:0;padding:0;color:#2a3644;font-weight:500;font-size:18px;line-height:26px;text-align:center}.l-content--main{width:100%;flex:1 1 auto;max-width:1070px;padding:35px 20px 90px;margin:0 auto}.l-content--main h1{color:#2a3644;font-weight:500;font-size:22px;line-height:29px}.l-content--main h2{color:#2a3644;font-weight:500;font-size:19px;line-height:25px}.l-content--main h3{color:#2a3644;font-weight:500;font-size:16px;line-height:20px}.l-content--divisions,.l-content--regions{width:100%;max-width:1040px;padding-right:20px;padding-left:20px;margin:0 auto 40px}.l-content--faq{width:100%;flex:1 1 auto;max-width:1070px;padding:35px 20px 90px;margin:0 auto}.l-content--faq h1{color:#2a3644;font-weight:500;font-size:22px;line-height:29px}.l-content--faq h2{color:#2a3644;font-weight:500;font-size:19px;line-height:25px}.l-content--faq h3{color:#2a3644;font-weight:500;font-size:16px;line-height:20px}.l-content--membership{width:100%;flex:1 1 auto;max-width:1070px;padding:35px 20px 90px;margin:0 auto}.l-content--membership h1{color:#2a3644;font-weight:500;font-size:22px;line-height:29px}.l-aside--position{background-color:#f6f9ff}.l-aside--divisions,.l-aside--regions{z-index:50}.l-aside--close{position:fixed;top:0;padding:14px 17px;cursor:pointer}.l-main{flex:1 1 400px}.l-main--content{background-color:#fff;padding:30px 20px}.l-main--content img{max-width:100%;height:auto}.l-main--divisions,.l-main--regions{flex:1 1 600px}.l-main--position{overflow:hidden}.l-footer{background:#1d2a3a;background:var(--color--blue-dark);color:#fff;padding-top:20px}.l-map{height:330px;margin-bottom:35px}.l-map--cities{height:625px}.l-map--cities--panevezys-inner{height:305px}.l-nav--close{top:10px;right:10px;padding:20px;color:#fff}.l-nav--close,.l-nav--open{position:absolute;cursor:pointer}.l-nav--open{top:0;right:0;padding:24px 20px}.l-section{padding:20px 0}.l-section--search-page{background-color:#111d1e}.l-section--vdb{background-color:#086335}.l-section--front-page{margin-bottom:2px;background-color:#fff}.l-section--front-page .l-section--inner,.l-section--sales-page .l-section--inner{max-width:870px;padding-right:20px;padding-left:20px}.l-section--inner{width:100%;max-width:1030px;margin:0 auto}.l-section--inner-extended{width:100%;max-width:1170px;margin:0 auto}.l-section--landing-1{background-color:#515e70}.l-section--landing-1,.l-section--recommend{display:flex;align-items:flex-end;padding:0!important;height:240px}.l-section--recommend{background-color:#3eb0b1}.l-section--landing-3,.l-section--landing-4,.l-section--landing-5{display:flex;align-items:flex-end;padding:0!important;background-color:#515e70;height:240px}.o-btn{display:inline-block;border:0;padding:11px 24px 10px;cursor:pointer;border-radius:3px;font-weight:500;line-height:15px;text-decoration:none;font-family:inherit}.o-nav{margin:0}.c-breadcrumbs,.o-nav{padding:0;list-style:none}.c-breadcrumbs{display:flex;margin:-5px 0 10px;width:100%;font-size:13px;height:20px;color:#6f7479;overflow:hidden}.c-breadcrumbs li{overflow:hidden;flex:0 0 auto}.c-breadcrumbs li:last-child{flex:1 1 auto}.c-breadcrumbs a{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-decoration:none}.c-breadcrumbs a:hover{text-decoration:underline}.c-btn--header{font-size:14px;font-weight:500}.c-btn--footer{display:block;text-align:center}.c-btn--main{color:#fff;background:#1fb299;background:var(--color--green);border:2px solid #1fb299;border:2px solid var(--color--green)}.c-btn--main:hover{background:#149a83;background:var(--color--green-darker);border-color:#149a83;border-color:var(--color--green-darker)}.c-btn--phone{color:#fff;background:#1fb299;background:var(--color--green);border:2px solid #1fb299;border:2px solid var(--color--green);border-radius:44px;overflow:hidden;height:44px;line-height:24px;margin:-15px 0 15px;padding:9px 15px 8px}.c-btn--phone svg{float:left;margin:0 10px 0 0}.c-btn--phone:hover{background:#149a83;background:var(--color--green-darker);border-color:#149a83;border-color:var(--color--green-darker)}.c-btn--phone-alt{color:#fff;background:#da2128;border:2px solid #da2128;overflow:hidden;height:44px;line-height:24px;margin:-10px 0 15px;padding:9px 15px 8px}.c-btn--phone-alt svg{float:left;margin:0 20px 0 0}.c-btn--phone-alt:hover{background:#a70000;border-color:#a70000}.c-btn--disabled{color:#bbb;background:#6f7479;border-color:#6f7479;outline:none;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.c-btn--disabled:hover{color:#bbb;background:#6f7479;cursor:not-allowed;border-color:#6f7479}.c-btn--vdb{color:#fff;background:#ff7046;border-color:#ff7046}.c-btn--vdb:hover{background:#ff501d;border-color:#ff501d}.c-btn--alt{padding:10px 15px;background:#e8f0ff;color:#004ed4}.c-btn--alt:after{float:right;margin:6px 0 0 35px;content:"";width:7px;height:7px;border:1px solid #004ed4;border-width:2px 2px 0 0;transform:rotate(45deg)}.c-btn--alt:hover{background-color:#dde6f5}.c-btn--fill{width:100%}.c-btn--fit{flex:1 1 20%}.c-btn--fit+.c-btn--fit{margin-left:20px}.c-btn--max-fill{width:100%;max-width:320px}.c-btn--search{min-width:180px;border-radius:0 3px 3px 0;text-align:center}.c-btn--search-small{margin:9px;min-width:133px;text-align:center}.c-btn--slim{color:#14a28a;background:none;text-align:center;border:2px solid #1fb299}.c-btn--slim:hover{border-color:#149a83;border-color:var(--color--green-darker);background-color:#149a83;background-color:var(--color--green-darker);color:#fff}.c-btn--filter{color:#2a3644;font-size:15px;line-height:26px;text-align:center;background:#fff;border-radius:3px;padding:6px 10px 6px 7px}.c-categories{display:flex;list-style:none;margin:-5px 0 0;padding:0;width:100%;font-size:13px;height:20px;color:#6f7479;overflow:hidden}.c-categories li{overflow:hidden;flex:0 0 auto}.c-categories li:last-child{flex:1 1 auto}.c-categories a{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-decoration:none}.c-categories a:hover{text-decoration:underline}.c-categories--sep{padding:0 7px}.c-cookies-warning{display:none}.c-contact{padding:20px 0}.c-contact--inner{max-width:1000px;padding:0 10px;margin:0 auto}.c-contact--content{color:#2a3644;font-weight:500;line-height:29px;padding:15px 0 20px 15px}.c-contact--content h3{margin:0 0 15px;font-size:25px;color:#2a3644;font-weight:500}.c-contact--content p{margin:0 0 20px}.c-contact--content img{max-width:100%;height:auto}.c-contact--form{max-width:420px}.c-contact-landing-1{padding:10px 0}.c-contact-landing-1--inner{max-width:1000px;padding:0 10px;margin:0 auto}.c-contact-landing-1--content{color:#2a3644;font-weight:500;line-height:29px;padding:15px 0 20px 15px}.c-contact-landing-1--content img{max-width:100%;height:auto}.c-contact-landing-1--img{margin-top:40px}.c-contact-landing-1--form{max-width:420px}.c-contact-landing-2{padding:90px 0 0;background-position:0 0;background-repeat:no-repeat;background-size:cover}.js.no-webp .c-contact-landing-2,.no-js .c-contact-landing-2{background-image:url(/wp-content/themes/biuro/i/sections/landing-2-xl.jpg)}.js.webp .c-contact-landing-2{background-image:url(/wp-content/themes/biuro/i/sections/landing-2-xl.webp)}.c-contact-landing-2--content{max-width:440px;color:#fff;font-weight:500;line-height:29px;padding:25px 20px 20px}.c-contact-landing-2--content img{max-width:100%;height:auto}.c-contact-landing-2--content h1{color:#fff;font-weight:600;font-size:23px;line-height:32px;margin:0 0 20px}.c-contact-landing-2--content p{font-size:15px;line-height:25px}.c-contact-landing-2--content p span{display:block;overflow:hidden}.c-contact-landing-2--img{margin:40px 0 0 45px;max-width:300px}.c-contact-landing-3{padding:10px 0}.c-contact-landing-3--inner{max-width:990px;padding:0 10px;margin:0 auto}.c-contact-landing-3--content{color:#2a3644;font-weight:500;padding:15px 0 20px 15px}.c-contact-landing-3--content img{max-width:100%;height:auto}.c-contact-landing-3--content span{display:block;overflow:hidden;line-height:22px;padding:2px 0 0}.c-contact-landing-3--img{margin-top:40px}.c-contact-landing-3--form{max-width:420px}.c-contact-landing-4{padding:10px 0}.c-contact-landing-4--inner{max-width:1000px;padding:0 10px;margin:0 auto}.c-contact-landing-4--content{color:#2a3644;font-weight:500;padding:15px 0 20px 15px}.c-contact-landing-4--content img{max-width:100%;height:auto}.c-contact-landing-4--content span{display:block;overflow:hidden;line-height:22px;padding:2px 0 0}.c-contact-landing-4--img{margin-top:40px}.c-contact-landing-4--form{max-width:420px}.c-contact-landing-5{padding:10px 0}.c-contact-landing-5--inner{max-width:1000px;padding:0 10px;margin:0 auto}.c-contact-landing-5--content{color:#2a3644;font-weight:500;padding:15px 0 20px 15px}.c-contact-landing-5--content img{max-width:100%;height:auto}.c-contact-landing-5--content span{display:block;overflow:hidden;line-height:22px;padding:2px 0 0}.c-contact-landing-5--content h2{font-weight:700;font-size:24px;line-height:34px;color:#000}.c-contact-landing-5--content-inner-alt p,.c-contact-landing-5--content-inner p{font-size:16px;line-height:20px}.c-contact-landing-5--content-inner-alt svg,.c-contact-landing-5--content-inner svg{color:#da2128}.c-contact-landing-5--content-inner-alt{max-width:380px;padding-top:10px;font-weight:900}.c-contact-landing-5--content-inner-alt b{color:#da2128}.c-contact-landing-5--img{margin-top:40px}.c-contact-landing-5--form{max-width:390px}.c-divisions{display:flex;flex-wrap:wrap}.c-division{flex:0 0 auto;height:30px;margin:0 10px 10px 0;padding:0 20px;background-color:#e8f0ff;line-height:30px;white-space:nowrap}.c-feedbacks{padding:30px 0;background:linear-gradient(134.06deg,#fff,#cbe2ec);overflow:hidden}.c-feedbacks--inner{position:relative;overflow:hidden;height:420px;margin:-20px auto -40px;width:100%;padding:20px 10px 0}.c-feedbacks--heading{color:#2a3644;margin:0 0 20px;padding:0 30px;font-size:18px;line-height:26px;font-weight:500;text-align:center}.c-feedbacks--section{max-width:300px;height:350px;margin:0 auto}.c-feedbacks--section-inner{position:relative;height:300px!important;max-width:100%;background-color:#fff;border-radius:3px;padding-top:50px}.swiper-slide-active .c-feedbacks--section-inner{box-shadow:-1px 15px 46px 0 rgba(192,210,231,.5)}.c-footer-action{position:fixed;right:0;bottom:0;left:0;padding:15px 23px;background:#fff;box-shadow:0 1px 39px -23px #454c54;z-index:90}.c-footer-section:first-child{flex:5 0 15%}.c-footer-section:nth-child(4){flex:1 0 15%}.c-footer-separator{margin-bottom:25px;border-color:#fff;border-width:2px 0 0;opacity:.29}.c-form{position:relative}.c-form--header{color:#069980;font-size:21px;font-weight:700;margin:-8px 0 20px;padding:0}.c-form--action{position:absolute;top:-88px;left:-9999px;width:1px}.c-form--action-position{top:-58px}.c-form--employees,.c-form--employers{box-shadow:0 1px 31px -23px #6a7481}.c-form--employees,.c-form--employers,.c-form--position{padding:28px 20px 20px;border-radius:3px;background-color:#fff}.c-form--recommend{border-radius:3px;background-color:#fff;box-shadow:0 1px 31px -23px #6a7481;padding:0 15px 20px}.c-form--cols{margin:0 -15px}.c-form--col{flex:1 1 50%;padding:25px 15px 0}.c-form--col--about{background:linear-gradient(180deg,#a1fff0,hsla(0,0%,100%,0) 168px)}.c-form--col--about-friend{background:linear-gradient(180deg,#cfe1fc,hsla(0,0%,100%,0) 168px)}.c-form--success{margin:-28px -20px 20px;padding:28px 20px 20px;border-radius:3px 3px 0 0;text-align:center;color:#27b199;line-height:25px;background:#e5fdf9;font-weight:500}.c-form--headline{text-transform:uppercase;margin-bottom:20px;font-weight:500;font-size:18px}.c-form--headline--about{color:#14b399}.c-form--headline--about-friend{color:#004ed7}.c-form--row{position:relative;margin-bottom:20px}.c-form--row-sticky{display:flex}.c-form--label{display:block;color:#2a3644;font-size:15px;line-height:18px;margin-bottom:4px;font-weight:500}.c-form--input-file-wrap{position:relative;overflow:hidden}.c-form--input{width:100%;padding:10px;background:none;border:1px solid #d4d4d4;border-radius:3px;font-size:15px;font-family:inherit}.c-form--input:focus{border-color:#d4d4d4!important}.c-form--textarea{width:100%;padding:10px;background:none;border:1px solid #d4d4d4;border-radius:3px;font-size:15px;font-family:inherit}.c-form--textarea:focus{border-color:#d4d4d4!important}.c-form--input-file{position:absolute;left:0;top:0;width:100%;height:100%;cursor:pointer;z-index:10;opacity:0}.c-form--input-file:hover+button{background:#1fb299;background:var(--color--green);color:#fff}.c-form--input-file-btn{width:100%;padding:10px 10px 6px;background-color:#f0f0f0;border:1px solid #f0f0f0;border-radius:3px;font-size:15px;font-family:inherit;text-align:center}.c-form--input-file-text{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c-form--submit-wrap{padding:10px 0}.c-form--checkbox-wrap{display:flex;position:relative}.c-form--checkbox{position:absolute;top:0;left:0;visibility:hidden}.c-form--checkbox:checked+label:before{border-color:#d4d4d4}.c-form--checkbox:checked+label:after{content:"✔"}.c-form--label-checkbox{position:relative;margin:0 0 0 31px;color:#6f7479;font-size:12px;line-height:17px}.c-form--label-checkbox:before{content:"";position:absolute;top:0;left:-31px;height:18px;width:18px;border:1px solid #d4d4d4;border-radius:3px;cursor:pointer}.c-form--label-checkbox:after{content:"";position:absolute;top:-2px;left:-28px;width:20px;height:20px;border-radius:3px;color:#1fb299;color:var(--color--green);font-size:22px;cursor:pointer}.c-form--label-infobox,.c-form--label-recaptcha{color:#6f7479;font-size:12px;line-height:17px}.c-form--validation{background-color:#fff;margin-top:5px;padding:10px 15px;border:1px solid;font-size:13px;line-height:20px;z-index:20}.c-heading{display:flex;flex-direction:column;justify-content:center}.c-heading h1{margin:0 0 18px;padding:0;color:#2a3644;font-size:21px;font-weight:500;line-height:32px}.c-heading--landing-1 h1{max-width:230px;padding:0 20px}.c-heading--landing-1 h1,.c-heading--landing-3 h1{color:#fff;font-size:21px;line-height:32px}.c-heading--landing-3 h1 span{color:#19c5a7}.c-heading--landing-4{color:#fff;padding:0 20px}.c-heading--landing-4 h1{color:#fff;font-size:21px;line-height:32px}.c-heading--landing-4 h1 span{color:#19c5a7}.c-heading--landing-5{color:#fff;padding:0 15px}.c-heading--landing-5 h1{color:#fff;font-weight:700;font-size:24px;line-height:28px}.c-heading--landing-5 h1 span{color:#19c5a7}.c-heading--recommend-friend h1{max-width:420px;color:#fff;font-size:26px;line-height:37px;padding:0 20px 20px}.c-heading--recommend-friend h1 span{display:inline-block;background:#004ed4;font-weight:700;padding:3px 10px 1px;border-radius:6px}.c-ico--search{margin:0 3px -3px 0}.c-ico--location{left:18px}.c-ico--area,.c-ico--location{position:absolute;top:50%;transform:translateY(-50%);margin-top:-1px}.c-ico--area{left:14px}.c-ico--phone{float:left;margin:-2px 10px 0 -29px}.c-ico--phone-recommend{float:left;margin:0 15px 0 0}.c-ico--email{float:left;margin:2px 10px 0 -30px}.c-ico--address{float:left;margin:0 12px 0 -27px}.c-ico--city,.c-ico--filter{float:left;margin:3px 8px 0 3px}.c-ico--city--job-section{float:left;margin:0 13px 0 0}.c-ico--field--job-section{float:left;margin:0 11px 0 0;width:18px;height:17px}.c-ico--type--job-section{float:left;margin:0 13px 0 0}.c-ico--time{float:left;margin:2px 16px 0 0}.c-ico--offer{float:left;margin:1px 17px 0 0}.c-ico--pen{float:left;margin:5px 17px 0 0}.c-ico--easy{float:left;margin:0 17px 0 0}.c-ico--edit{float:left;margin:-1px 13px 0 1px}.c-ico--euro{float:left;margin:0 15px 0 0}.c-ico--calendar{float:left;margin:0 20px 0 0}.c-ico--lunch{float:left;margin:2px 18px 0 0}.c-ico--transport{float:left;margin:2px 20px 0 0}.c-ico--attachment{margin:-2px 4px -1px 0;opacity:.5}.c-ico--medical{float:left;margin:1px 21px 0 0}.c-ico--house{float:left;margin:5px 10px 0 -2px}.c-job--title{margin:0 0 15px;padding:0;color:#2a3644;font-weight:500;font-size:22px;line-height:29px}.c-job--content{line-height:25px;color:#2a3644}.c-job--content h3{color:#069980;font-size:19px;font-weight:700;margin:0 0 3px;padding:0}.c-job--content h3:nth-child(n+1){margin-top:30px}.c-job--content ul{margin:0 0 1.6rem;padding:0;list-style:none}.c-job--content li:before{content:"";display:inline-block;width:14px;height:8px;margin:0 5px 1px 0;background:url(/wp-content/themes/biuro/i/ico--job-arrow.svg)}.c-job--action{padding:30px 0;display:flex}.c-jobs--inner-custom{max-width:990px;margin-right:auto;margin-left:auto;padding-right:10px;padding-left:10px}.c-jobs--table{width:100%;margin:0 0 20px;padding:0}.c-jobs--headline{margin:0 0 25px;padding:20px 20px 0}.c-jobs--col{background:#fff;vertical-align:middle;color:#6f7479;padding:10px 15px}.c-jobs--anchor{color:#004ed4;font-weight:500}.c-jobs--anchor,.c-jobs--anchor-alt{display:block;line-height:18px;text-decoration:none}.c-jobs--anchor-alt{color:#2a3644}.c-jobs--more{margin-bottom:50px}[href="https://maps.google.com/?q="]{display:none!important}.c-jobs-section{margin:0 20px 20px 0;padding:28px 28px 23px}.c-jobs-section--heading{margin:0 0 15px}.c-jobs-section--list{margin:0;padding:0;list-style:none}.c-logo{width:81px;margin-right:89px;padding:11px 0;text-decoration:none}.c-logo,.c-logo--svg{display:block}.c-members{display:flex;flex-wrap:wrap;padding:20px}.c-modal{position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(42,54,68,.86);z-index:8000}.c-modal--inner{position:absolute;top:50%;left:50%;max-width:94%;width:606px;height:314px;padding:56px 20px 20px;background-color:#fff;transform:translate(-50%,-50%);text-align:center}.c-modal--inner svg{display:block;margin:0 auto 23px}.c-modal--inner p{margin-bottom:20px}.c-modal--inner .c-btn--main{min-width:208px}.c-nav--main{display:flex;font-size:14px}.c-nav--sub{display:none}.c-nav--main-item{position:relative;z-index:500}.c-nav--main-anchor{display:block;padding:5px 0 4px;font-weight:500;color:#fff;text-decoration:none}.c-nav--lang-wrap{width:74px;height:32px}.c-nav--lang-item{padding:6px 0}.c-nav--lang-item:nth-child(n+2){display:none}.c-phone{white-space:nowrap;padding:12px 0 10px;color:inherit;font-weight:500;font-size:14px}.c-phone svg{float:left;margin:-6px 5px 0 0}.c-popup{display:none}.c-recommend-friend{padding:10px 0}.c-recommend-friend--inner{max-width:1170px;padding:0 10px;margin:0 auto}.c-recommend-friend--content{color:#2a3644;font-weight:500;line-height:22px;padding:15px 0 20px}.c-recommend-friend--content img{max-width:100%;height:auto}.c-recommend-friend--content span{display:block;line-height:22px;overflow:hidden}.c-recommend-friend--form{max-width:604px}.c-recommend{display:block;background-color:#3bacad;min-height:170px;margin:0 10px 20px;padding:20px;border-radius:6px;text-decoration:none}.c-recommend-top{display:flex;min-height:62px}.c-recommend--headline{display:block;color:#fff;max-width:180px;margin-bottom:20px;font-size:21px;font-weight:500}.c-recommend--anchor{color:#fff;font-size:15px}.c-search{display:flex;background-color:#fff;border-radius:3px}.c-search--col{position:relative;flex:1 1 auto;background-color:#fff}.c-search--col .awesomplete{position:absolute;top:0;right:0;left:0;height:100%;display:flex;flex-direction:column}.c-search--col ul{top:57px;padding-top:10px;overflow-x:hidden;max-height:350px;overflow-y:auto}.c-search--col li{padding:10px 15px;margin-bottom:10px;cursor:pointer}.c-search--col li:hover{color:#000}.c-search--col-location{border-radius:3px 3px 0 0}.c-search--input{border:0;padding:0 0 0 44px;margin:0 40px 0 0;height:60px;line-height:60px;background:none}.c-search--input:focus{outline:none}.c-search--filters{padding:10px;display:flex;justify-content:space-between}.l-section--front-page .c-search{box-shadow:6px 10px 48px 0 #d4dbe4}.c-search--reset{display:none}.c-search--ico-clear{padding:13px 18px 13px 17px}.c-search--ico-clear,.c-search--ico-toggle{position:absolute;top:50%;right:0;cursor:pointer;transform:translateY(-50%)}.c-search--ico-toggle{padding:18px 16px;color:#b8bcc1}.c-search--ico-toggle .c-ico--down{display:block}.c-search--ico-toggle .c-ico--up,.c-search--ico-toggle.is-open .c-ico--down{display:none}.c-search--ico-toggle.is-open .c-ico--up{display:block}.c-sections{max-width:1000px;margin-right:auto;margin-left:auto;align-items:center;padding:20px}.c-sections--item{position:relative;height:211px;margin-bottom:30px}.c-services{padding:20px}.c-services--item{position:relative;height:245px}.c-services--toggle{display:none}.c-share{margin-bottom:20px}.c-share--heading{margin:0;padding:20px 0 10px;font-weight:500;text-align:center}.c-share--options{flex-wrap:wrap}.c-share--option,.c-share--options{display:flex;justify-content:center}.c-share--option{position:relative;height:36px;flex:0 0 50px;border-radius:3px;margin:0 3px 10px;text-decoration:none;align-items:center}.c-share--option-facebook{background-color:#4367b0}.c-share--option-facebook:hover{background-color:#2f4f90}.c-share--option-messenger{background-color:#1983fa}.c-share--option-messenger:hover{background-color:#1b6fcc}.c-share--option-email{background-color:#2a3644}.c-share--option-email:hover{background-color:#000}.c-share--option-copy{background-color:#858585}.c-share--option-copy:hover{background-color:#5c5c5c}.c-share--option-phone{background-color:#25d366}.c-share--option-phone:hover{background-color:#1baf52}.c-tooltip{position:absolute;pointer-events:none;opacity:0}.c-trust{background:linear-gradient(134.06deg,#70b7d5,#7bcbcf)}.c-trust--inner{align-items:center;padding-top:25px;padding-bottom:45px}.c-trust--heading{flex:1 1 auto;margin:0 0 35px;color:#fff}.c-trust--logos{flex:10 1 auto;display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.c-values--inner{padding-top:20px;padding-bottom:20px}.c-values--section{max-width:250px}.c-values--heading{min-height:34px;font-size:35px;line-height:41px}.c-vdb--top{min-height:68px;background:#02bf5f;padding:14px 0}.c-vdb--top-inner{max-width:1050px;margin:0 auto;padding:0 10px;display:flex;align-items:center}.c-vdb--top-img{flex:0 0 39px;margin-right:38px}.c-vdb--top-content{flex:1 1 auto;color:#fff;margin:0;padding:0 10px 0 0;font-size:18px;line-height:25px}.c-vdb--section{margin:0 20px 20px 0;padding:28px 28px 23px;border-radius:3px;background-color:#fff}.c-vdb--section-bottom{max-width:360px;margin:0 auto 20px;border:20px solid #f8f8f8}.c-vdb--section-img{display:block;margin:0 auto 15px}.c-vdb--section-heading{font-size:21px;font-weight:500;line-height:27px}.c-vdb--section-content{line-height:23px}.c-vdb--bottom{min-height:68px;background:#4b5561 url(/wp-content/themes/biuro/i/vdb/bottom.png) no-repeat 50% 50%;background-size:cover;padding:46px 0}.c-vdb--bottom-inner{max-width:1050px;margin:0 auto;padding:0 10px;display:flex;align-items:center;justify-content:center}.c-vdb--bottom-heading{margin:0 38px 0 0;padding:0;color:#fff;font-size:36px;line-height:42px;font-weight:500}.c-vdb--bottom-content{color:#fff;margin:0;padding:0;line-height:23px}.t-motherson .c-btn--main{background:#da2128;border:2px solid #da2128}.t-motherson .c-btn--main:hover{background:#a70000;border-color:#a70000}.u-fill--inherit{fill:currentColor}.u-fill--logo{fill:#149a83}.u-hidden{display:none}.visually-hidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}@media (min-width:60em){body{padding-top:117px;font-size:1.5rem;font-size:var(--typo--font-size);line-height:1.2;line-height:var(--typo--line-height)}h1{font-size:25px;line-height:38px;margin:0 0 25px}h2{font-size:21px;margin:0 0 21px}h2,h3{line-height:30px}h3{font-size:18px;margin:0 0 18px}.l-header{margin-bottom:47px}.l-header:before{content:"";position:absolute;top:100%;left:0;width:100%;height:47px;background:#1d2a3a;background:var(--color--blue-dark)}.l-content{display:flex}.l-content--position-banner{margin:-20px auto 20px}.l-content--position{padding:40px 20px}.l-content--position-inner{display:flex;margin:0 auto 140px}.l-content--position-inner .l-main{padding:70px 55px 40px 57px}.l-content--heading{padding-left:320px;padding-top:40px;padding-bottom:25px}.l-content--heading h1{font-size:25px;line-height:29px;text-align:right}.l-content--main h1{font-size:25px;line-height:38px}.l-content--main h2{font-size:21px;line-height:30px}.l-content--main h3{font-size:18px;line-height:30px}.l-content--divisions{display:flex;margin:0 auto 40px}.l-content--regions{display:flex;margin:0 auto 200px}.l-content--faq h1{font-size:25px;line-height:38px}.l-content--faq h2{font-size:21px;line-height:30px}.l-content--faq h3{font-size:18px;line-height:30px}.l-content--membership h1{font-size:25px;line-height:38px}.l-aside{flex:0 0 280px}.l-aside--position{flex:0 0 400px;padding:70px 40px;max-width:400px}.l-aside--position--wide{flex:1 1 280px;padding:70px 55px;max-width:470px}.l-aside--divisions,.l-aside--regions{flex:0 0 385px;margin:-315px 0 0 55px}.l-aside--close{display:none}.l-main--content{padding:40px 50px}.l-footer{padding-top:70px}.l-map--cities--panevezys-inner{height:513px}.l-nav--wrap{flex:1 1 100%;display:flex;align-items:center}.l-nav{flex:1 1 auto}.l-nav--close,.l-nav--open{display:none}.l-section{padding:30px 0}.l-section--front-page{height:380px;margin-bottom:92px}.l-section--sales-page{height:380px}.l-section--landing-1{height:348px}.l-section--recommend{height:355px}.l-section--landing-3,.l-section--landing-4,.l-section--landing-5{height:348px}.c-breadcrumbs{margin:-40px 0 0;height:40px}.c-btn--header{margin-right:28px}.c-btn--phone-alt{height:68px;margin:10px 0 35px;padding:21px 28px 20px}.c-categories{margin:-20px 0 0}.c-contact{padding:50px 0}.c-contact--inner{display:flex;justify-content:space-between}.c-contact--content{flex:1 1 40%;max-width:500px;padding:75px 0 0 90px}.c-contact--form{flex:1 1 40%}.c-contact-landing-1{padding:30px 0 40px}.c-contact-landing-1--inner{display:flex;justify-content:space-between}.c-contact-landing-1--content{flex:1 1 40%;max-width:500px;padding:0 0 0 90px}.c-contact-landing-1--form{flex:1 1 40%;margin-top:-200px}.c-contact-landing-2{padding:195px 0 50px}.c-contact-landing-2--inner{display:flex;justify-content:space-between;max-width:940px;margin:0 auto;border-radius:3px;background:rgba(0,66,180,.78)}.c-contact-landing-2--content{flex:1 1 40%;max-width:500px;padding:56px 40px 0}.c-contact-landing-2--content h1{margin:0 0 35px;font-size:29px;line-height:46px}.c-contact-landing-2--content p{font-size:16px}.c-contact-landing-2--form{flex:1 1 40%;max-width:420px}.c-contact-landing-3{padding:20px 0}.c-contact-landing-3--inner{display:flex;justify-content:space-between}.c-contact-landing-3--content{flex:1 1 40%;max-width:500px;padding:0}.c-contact-landing-3--form{flex:1 1 40%;margin-top:-180px}.c-contact-landing-4{padding:20px 0}.c-contact-landing-4--inner{display:flex;justify-content:space-between}.c-contact-landing-4--content{flex:1 1 40%;max-width:500px;padding:0 0 0 90px}.c-contact-landing-4--form{flex:1 1 40%;margin-top:-180px}.c-contact-landing-5{padding:20px 0}.c-contact-landing-5--inner{display:flex;justify-content:space-between}.c-contact-landing-5--content{flex:1 1 40%;max-width:510px}.c-contact-landing-5--content-inner{-moz-columns:2;column-count:2}.c-contact-landing-5--content-inner p{width:200px;height:50px}.c-contact-landing-5--content-inner-alt p,.c-contact-landing-5--content-inner p{padding:15px 0}.c-contact-landing-5--form{flex:1 1 40%;margin-top:-244px}.c-feedbacks{padding:50px 0 70px}.c-feedbacks--inner{max-width:720px;padding:20px 0 0}.c-feedbacks--heading{font-size:25px;line-height:29px;margin:0 0 40px}.c-footer-action{display:none}.c-footer-sections{display:flex}.c-footer-section{flex:10 0 15%}.c-form--header{font-size:24px}.c-form--action{top:-128px}.c-form--employees,.c-form--employers{padding:38px 35px 20px}.c-form--position{margin:-40px -15px 20px;box-shadow:0 1px 31px -23px #6a7481}.c-form--recommend{padding:0 33px 20px}.c-form--cols{display:flex;margin:0 -33px}.c-form--col--about,.c-form--col--about-friend{padding:42px 24px 0 33px}.c-form--success{margin:-38px -35px 20px;padding:28px 35px 20px}.c-form--headline{margin-bottom:30px}.c-form--row-sticky .o-btn:nth-child(n+2){display:none}.c-form--validation{position:absolute;top:50%;right:100%;min-width:200px;margin-top:11px;transform:translate(-30px,-50%)}.c-heading h1{font-size:34px;font-weight:700;line-height:51px}.c-heading--front-page,.c-heading--sales-page{height:320px}.c-heading--landing-1 h1{max-width:500px;font-size:31px;line-height:45px}.c-heading--landing-1{padding-left:110px}.c-heading--landing-3 h1{max-width:500px;font-size:36px;line-height:45px}.c-heading--landing-3{padding-left:30px}.c-heading--landing-4 h1{max-width:500px;font-size:36px;line-height:45px}.c-heading--landing-4{padding-left:110px}.c-heading--landing-5 h1{max-width:500px;font-size:36px;line-height:45px}.c-heading--recommend-friend h1{max-width:500px;font-size:32px;line-height:56px;padding:0 20px}.c-job--title{font-size:30px;line-height:39px;margin:0 0 40px}.c-jobs--col{border-bottom:1px solid #f8f8f8;border-bottom:1px solid var(--color--gray-light)}.c-jobs--anchor{display:flex;min-height:38px;align-items:center}.c-jobs--more{margin-bottom:70px}.c-nav--main-item{height:70px;margin-right:26px;padding:23px 0 0}.c-nav--main-anchor{color:#1d2a3a;color:var(--color--blue-dark)}.c-nav--lang-wrap{position:relative;width:70px}.c-phone{margin-right:35px}.c-recommend-friend{padding:30px 0 40px}.c-recommend-friend--inner{display:flex;justify-content:space-between}.c-recommend-friend--content{flex:1 1 40%;max-width:500px;line-height:29px}.c-recommend-friend--form{flex:1 1 40%;margin-top:-200px}.c-recommend{margin:0 0 20px}.l-aside--position--wide .c-recommend{margin:0 -15px 20px}.c-search{height:60px}.c-search--col-location{border-right:1px solid rgba(178,182,187,.46);border-radius:3px 0 0 3px}.c-search--filters{display:none}.l-section--front-page .c-search{height:70px}.l-section--front-page .c-search--input{height:70px;line-height:70px}.c-sections{padding:50px 20px 135px}.c-sections--inner{display:flex;flex-wrap:wrap;justify-content:space-between}.c-sections--item{flex:0 0 300px}.c-services{display:flex;flex-wrap:wrap;align-items:center;padding-top:64px;padding-bottom:64px;justify-content:space-between}.c-services--item{flex:0 0 253px}.c-trust--inner{display:flex;flex-wrap:wrap;padding-top:64px;padding-bottom:64px}.c-trust--heading{margin:0}.c-trust--logos{justify-content:space-around}.c-values--inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding-top:60px;padding-bottom:40px}.c-values--section{flex:0 0 40%;max-width:280px}.c-values--heading{min-height:66px;font-size:45px;line-height:53px}.c-vdb--section-bottom{display:none}}@media (max-width:59.999em){.l-inner--header{align-items:flex-start}.l-content--position{background:#f6f9ff;flex:1 1 auto}.l-content--position+.l-footer{display:none}.l-content--faq,.l-content--main,.l-content--membership{padding:10px}.l-aside--position{padding-bottom:50px}.l-aside--divisions,.l-aside--regions{max-width:440px;margin:0 auto}.l-aside--search{display:none;position:fixed;top:0;width:310px;height:100%;overflow:auto;z-index:20}.l-aside--search:before{content:"";position:fixed;top:0;width:270px;bottom:0;background:#fff}.l-footer{padding-bottom:30px}.l-nav--wrap{display:none;position:fixed;top:0;left:0;width:100%;height:100%;overflow-y:auto;opacity:.97;background-color:#1d2a3a;z-index:500;border:1px solid #000;overflow:hidden;text-align:center;flex-direction:column;align-items:center}.l-nav{width:100%}.l-section--front-page{height:179px;margin-bottom:185px}.c-btn--search{flex:0 0 60px;border-radius:0 0 3px 3px}.c-contact,.c-contact-landing-1{max-width:440px;margin:0 auto}.c-contact-landing-2{margin:0 auto}.c-contact-landing-2--inner{padding:0 10px}.c-contact-landing-2--content{margin:0 auto;border-radius:3px 3px 0 0;background:rgba(0,66,180,.78)}.c-contact-landing-2--img{display:none}.c-contact-landing-2--form{background:linear-gradient(45.94deg,#fff,#cbe2ec);margin:0 -10px;padding:0 10px 10px}.c-contact-landing-2--form .c-form--employees{margin:0 auto;max-width:440px;border-radius:0 0 3px 3px}.c-contact-landing-3,.c-contact-landing-4,.c-contact-landing-5{max-width:440px;margin:0 auto}.c-divisions{margin-bottom:20px}.c-form--row-sticky{position:fixed;right:0;bottom:0;left:0;margin:0;padding:15px 23px;background:#fff;box-shadow:0 1px 39px -23px #454c54;z-index:90}.c-heading h1{margin:0 0 36px}.c-heading p{display:none}.c-heading--front-page h1{max-width:117px}.c-heading--landing-1,.c-heading--landing-3{max-width:440px;margin:0 auto}.c-heading--landing-3{padding:0 20px}.c-heading--landing-4,.c-heading--landing-5{max-width:440px;margin:0 auto}.c-heading--recommend-friend h1{margin:0 auto}.c-job--content{font-size:15px}.c-job--content h3{font-size:17px}.c-job--action{display:none}.c-jobs--headline{text-align:center}.c-jobs--col{float:left}.c-jobs--col-position{width:100%}.c-jobs--col-description{width:100%;padding-top:0}.c-jobs--col-city,.c-jobs--col-valid{width:50%}.c-nav--main{margin:115px 0 180px;padding:0 20px;width:100%;justify-content:space-between}.c-nav--main-item:first-child{text-align:left}.c-nav--main-item:first-child .c-nav--sub{left:0;right:auto}.c-nav--main-item{position:relative;flex:0 0 auto;text-align:right}.c-nav--lang-wrap{position:absolute;top:20px;left:20px}.c-phone{color:#fff;margin:0 0 30px}.c-recommend-friend{max-width:440px;margin:0 auto}.c-search{flex-direction:column;margin:0 20px}.l-section--search-page{padding:10px 0}.l-section--search-page .c-search{flex-direction:row;margin:0 10px;border-radius:3px}.l-section--search-page .c-search--col-location{display:none}.l-section--search-page .c-search--col-keyword{flex:1 1 auto;border-radius:3px 0 0 3px}.l-section--search-page .c-search--btn-text{display:none}.l-section--search-page .c-btn--search-small{min-width:35px;margin:5px;padding:9px 7px 8px 8px}.l-section--search-page .c-search--input{height:49px;padding:0 0 0 15px}.l-section--search-page .c-search--col ul{top:45px;border-top:3px solid #fff}.l-section--search-page .c-ico--area{display:none}.c-search--col{flex:0 0 60px}.c-search--col-keyword,.c-search--col-location{border-bottom:1px solid rgba(178,182,187,.46)}.l-section--front-page .c-search,.l-section--front-page .c-search--input{margin:0}.l-section--front-page .c-search--input:focus{box-shadow:0 0 2px 0 rgba(0,0,0,.2)}.c-search--reset{position:relative;display:block;padding-top:20px;text-align:center}.c-sections--item{max-width:380px;margin:0 auto 30px}.c-services--item{max-width:380px;margin:0 auto 20px}.c-trust--heading{text-align:center;font-size:18px}.c-values--inner{max-width:400px}.c-vdb--top-img{margin-right:18px}.c-vdb--top-content{font-size:16px;line-height:19px}.c-vdb--section-aside{display:none}.c-vdb--bottom-heading{margin:0 18px 0 0}}@media (min-width:30em){.c-btn--filter{padding:6px 15px 6px 12px}.c-ico--city,.c-ico--filter{margin:3px 15px 0 3px}.c-search--filters{padding:10px 20px}}@media (max-width:19.999em){.c-contact-landing-2{background-size:cover!important}}@media (max-width:37.499em){.c-contact-landing-2{background-size:250%}}@media (min-width:93.75em){.c-form--validation{left:100%;right:auto;transform:translate(30px,-50%)}}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -152,7 +152,7 @@ ...@@ -152,7 +152,7 @@
?> ?>
<script src="/wp-content/themes/biuro/js/main.min.js" async defer></script> <script src="/wp-content/themes/biuro/js/main-ab10603d.min.js" async defer></script>
<script src="/wp-content/themes/biuro/js/vendor/modernizr-custom.js" async defer></script> <script src="/wp-content/themes/biuro/js/vendor/modernizr-custom.js" async defer></script>
......
...@@ -46,15 +46,12 @@ ...@@ -46,15 +46,12 @@
// WP Pods fix for multisite // WP Pods fix for multisite
global $wpdb; global $wpdb;
global $biuroSettings;
$settings = pods( 'biuro_settings', array(
'limit' => -1,
));
$params = array( $params = array(
'orderby' => 'date DESC', 'orderby' => 'date DESC',
'where' => $where, 'where' => $where,
'limit' => $settings->field('workis_ad') ? 4 : 5 'limit' => $biuroSettings->field('workis_ad') ? 4 : 5
); );
if (get_current_blog_id() != 1): if (get_current_blog_id() != 1):
...@@ -72,7 +69,7 @@ ...@@ -72,7 +69,7 @@
if ( 0 < $jobs->total() ): if ( 0 < $jobs->total() ):
if ($settings->field('workis_ad')): if ($biuroSettings->field('workis_ad')):
get_template_part( 'template-parts/jobs/jobs', 'list-homepage' ); get_template_part( 'template-parts/jobs/jobs', 'list-homepage' );
else: else:
get_template_part( 'template-parts/jobs/jobs', 'list' ); get_template_part( 'template-parts/jobs/jobs', 'list' );
......
...@@ -1269,3 +1269,11 @@ add_action( 'admin_post_nopriv_newsletters_post', 'newsletters_post' ); ...@@ -1269,3 +1269,11 @@ add_action( 'admin_post_nopriv_newsletters_post', 'newsletters_post' );
$inEmployers = (is_page() && get_post_meta( $post->ID, 'section', true) == 'employers') ? true : false; $inEmployers = (is_page() && get_post_meta( $post->ID, 'section', true) == 'employers') ? true : false;
define('inEmployers', $inEmployers); define('inEmployers', $inEmployers);
if (function_exists('pods')):
$biuroSettings = pods( 'biuro_settings', array(
'limit' => -1,
));
define('biuroSettings', $biuroSettings);
endif;
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-500.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-500.woff2" crossorigin="anonymous" >
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-regular.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-regular.woff2" crossorigin="anonymous" >
<style><?php include 'css/core.min.css'; ?></style> <style><?php include 'css/core-37788b01fc.min.css'; ?></style>
<script> <script>
document.documentElement.classList.replace('no-js', 'js'); document.documentElement.classList.replace('no-js', 'js');
...@@ -39,13 +39,13 @@ ...@@ -39,13 +39,13 @@
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-300.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-300.woff2" crossorigin="anonymous" >
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-700.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-700.woff2" crossorigin="anonymous" >
<link rel="preload" href="/wp-content/themes/biuro/css/main.min.css" as="style" onload="this.rel='stylesheet'"> <link rel="preload" href="/wp-content/themes/biuro/css/main-8bae5e9909.min.css" as="style" onload="this.rel='stylesheet'">
<link rel="preconnect" href="https://www.gstatic.com"> <link rel="preconnect" href="https://www.gstatic.com">
<link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://fonts.gstatic.com">
<noscript> <noscript>
<link rel="stylesheet" href="/wp-content/themes/biuro/css/main.min.css"> <link rel="stylesheet" href="/wp-content/themes/biuro/css/main-8bae5e9909.min.css">
</noscript> </noscript>
<?php wp_head(); ?> <?php wp_head(); ?>
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-500.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-500.woff2" crossorigin="anonymous" >
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-regular.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-regular.woff2" crossorigin="anonymous" >
<style><?php include 'css/core.min.css'; ?></style> <style><?php include 'css/core-37788b01fc.min.css'; ?></style>
<script> <script>
document.documentElement.classList.replace('no-js', 'js'); document.documentElement.classList.replace('no-js', 'js');
...@@ -50,13 +50,13 @@ ...@@ -50,13 +50,13 @@
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-300.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-300.woff2" crossorigin="anonymous" >
<link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-700.woff2" crossorigin="anonymous" > <link rel="preload" as="font" type="font/woff2" href="/wp-content/themes/biuro/fonts/roboto-v19-cyrillic_latin_cyrillic-ext_latin-ext-700.woff2" crossorigin="anonymous" >
<link rel="preload" href="/wp-content/themes/biuro/css/main.min.css" as="style" onload="this.rel='stylesheet'"> <link rel="preload" href="/wp-content/themes/biuro/css/main-8bae5e9909.min.css" as="style" onload="this.rel='stylesheet'">
<link rel="preconnect" href="https://www.gstatic.com"> <link rel="preconnect" href="https://www.gstatic.com">
<link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://fonts.gstatic.com">
<noscript> <noscript>
<link rel="stylesheet" href="/wp-content/themes/biuro/css/main.min.css"> <link rel="stylesheet" href="/wp-content/themes/biuro/css/main-8bae5e9909.min.css">
</noscript> </noscript>
<?php <?php
......
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{7:function(e,t,n){"use strict";n.r(t);const o=e=>{if(!e)return;const t=e.parentNode.nextElementSibling;if(!t||!t.classList.contains("c-accordion--content"))return;const n=e.classList.contains("c-accordion--header--is-expanded");n?(e=>{const t=e.scrollHeight,n=e.style.transition;e.style.transition="",requestAnimationFrame(()=>{e.style.height=t+"px",e.style.transition=n,requestAnimationFrame(()=>{e.style.height="0px"})})})(t):(history.pushState({},"",e.hash),requestAnimationFrame(()=>{(e=>{const t=e.offsetTop-(Math.max(document.documentElement.clientWidth,window.innerWidth||0)<960?72:117);window.scrollTo({top:t,behavior:"smooth"}),e.blur()})(e),requestAnimationFrame(()=>{(e=>{const t=e.scrollHeight,n=t=>{e.removeEventListener("transitionend",n)};e.style.height=t+"px",e.addEventListener("transitionend",n)})(t)})})),e.classList.toggle("c-accordion--header--is-expanded",!n)};t.default=()=>{document.querySelectorAll(".c-accordion--content").forEach(e=>{e.classList.add("c-accordion--content--is-collapsed")}),window.location.hash&&o(document.querySelector(window.location.hash)),document.querySelectorAll(".js-accordion--header").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault(),o(e)})})}}}]);
\ No newline at end of file
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["accordion"],{
/***/ "./wp-content/themes/biuro/js/components/accordion/accordion.js":
/*!**********************************************************************!*\
!*** ./wp-content/themes/biuro/js/components/accordion/accordion.js ***!
\**********************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\nconst collapseContent = n => {\n const h = n.scrollHeight;\n const t = n.style.transition;\n n.style.transition = '';\n requestAnimationFrame(() => {\n n.style.height = h + 'px';\n n.style.transition = t;\n requestAnimationFrame(() => {\n n.style.height = 0 + 'px';\n });\n });\n};\n\nconst expandContent = n => {\n const h = n.scrollHeight;\n\n const done = e => {\n n.removeEventListener('transitionend', done);\n };\n\n n.style.height = h + 'px';\n n.addEventListener('transitionend', done);\n};\n\nconst scrollToSection = header => {\n const top = header.offsetTop - (Math.max(document.documentElement.clientWidth, window.innerWidth || 0) < 960 ? 72 : 117);\n window.scrollTo({\n top: top,\n behavior: 'smooth'\n });\n header.blur();\n};\n\nconst toggleSection = header => {\n if (!header) {\n return;\n }\n\n const node = header.parentNode.nextElementSibling;\n\n if (!node || !node.classList.contains('c-accordion--content')) {\n return;\n }\n\n const isOpen = header.classList.contains('c-accordion--header--is-expanded');\n\n if (isOpen) {\n collapseContent(node);\n } else {\n history.pushState({}, '', header.hash);\n requestAnimationFrame(() => {\n scrollToSection(header);\n requestAnimationFrame(() => {\n expandContent(node);\n });\n });\n }\n\n header.classList.toggle('c-accordion--header--is-expanded', !isOpen);\n};\n\nconst inititateAccordion = () => {\n document.querySelectorAll('.c-accordion--content').forEach(content => {\n content.classList.add('c-accordion--content--is-collapsed');\n });\n\n if (window.location.hash) {\n toggleSection(document.querySelector(window.location.hash));\n }\n\n document.querySelectorAll('.js-accordion--header').forEach(header => {\n header.addEventListener('click', e => {\n e.preventDefault();\n toggleSection(header);\n });\n });\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (inititateAccordion);\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/accordion/accordion.js?");
/***/ })
}]);
\ No newline at end of file
(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{10:function(t,e,i){"use strict";i.r(e);var n=i(5);const s=t=>{var e={"ą":"a","č":"c","ę":"e","ė":"e","į":"i","š":"s","ų":"u","ū":"u","ž":"z","ā":"a","ē":"e","ģ":"g","ī":"i","ķ":"k","ļ":"l","ņ":"n","õ":"o","ä":"a","ö":"o","ü":"u"};return t=(t=(t=t.trim()).toLowerCase()).replace(/[ąčęėįšųūžāēģīķļņõäöü]/g,t=>e[t])},r=t=>{const e=document.getElementById(t),i=document.querySelector(".js-toggle--"+t),r=document.querySelector(".js-clear--"+t);let o=!1;const u=(t,e,i,n)=>{const s="search-city"===e.id?"query":"city";fetch("/wp-json/api/v1/options?langID="+t+"&str="+i+"&type="+s).then(t=>t.json()).then(t=>{if(!t||!t.length)return;const i=t.map(t=>({label:t.name+" ("+t.total+")",value:t.name}));e.box.list=i,n?(e.box.evaluate(),e.box.close()):(e.focus(),e.box.evaluate())})},a=t=>{const e="search-city"===t.id?document.getElementById("search-query"):document.getElementById("search-city");!e||e.value&&t.value||(!e.value&&t.value?u(t.dataset.id,e,t.value,!0):t.value||(u(t.dataset.id,t,e.value),e.value||u(t.dataset.id,e,e.value,!0)))},l=(t,e=0)=>{setTimeout(()=>{o=t},e),i&&i.classList.toggle("is-open",t)};if(!e)return;const c=new n.a(e,{minChars:0,maxItems:1e3,sort:!1,filter:function(t,e){return-1!==s(t).indexOf(s(e))}});e.addEventListener("input",()=>{r&&r.classList.toggle("u-hidden",!e.value),i&&i.classList.toggle("u-hidden",!!e.value)}),e.addEventListener("focus",()=>{o||0!==c.ul.childNodes.length&&!c.ul.hasAttribute("hidden")?(l(!1),c.close(),e.blur()):(l(!0),c.evaluate())}),e.addEventListener("blur",()=>{const t=Array.isArray(c.suggestions)&&1===c.suggestions.length?c.suggestions[0]:null;t&&s(e.value)===s(t.value)&&(e.value=t.value)}),e.addEventListener("awesomplete-selectcomplete",()=>{e.blur(),a(e),r&&r.classList.remove("u-hidden"),i&&i.classList.add("u-hidden")}),e.addEventListener("awesomplete-close",()=>{l(!1,150)}),i&&i.addEventListener("click",t=>{o?c.close():e.focus()}),r&&r.addEventListener("click",()=>{e.value="",a(e),r&&r.classList.add("u-hidden"),i&&i.classList.remove("u-hidden")}),e.box=c},o=(t,e)=>{if(!t||!e)return;const i=new n.a(t,{minChars:0,maxItems:1e3,sort:!1,filter:function(t,e){return-1!==s(t).indexOf(s(e))},replace:function(t){this.input.value=t.label,e&&(e.value=t.value)}});t.addEventListener("focus",()=>{i.evaluate()}),t.addEventListener("blur",()=>{const n=Array.isArray(i.suggestions)&&1===i.suggestions.length?i.suggestions[0]:null;n&&s(t.value)===s(n.label)&&(t.value=n.label,e&&(e.value=n.value))})};e.default=()=>{const t=document.getElementById("search"),e=document.getElementById("search-city"),i=document.getElementById("search-query");e&&r("search-city"),i&&r("search-query"),t&&e&&i&&t.addEventListener("submit",t=>{e.value||i.value||(e.focus(),t.preventDefault())},!1),o(document.getElementById("form-city"),document.getElementById("form-city-id")),o(document.getElementById("recommend-form-city"),document.getElementById("recommend-form-city-id"))}},5:function(t,e,i){"use strict";(function(t){e.a=function(){var e=function(t,i){var n=this;e.count=(e.count||0)+1,this.count=e.count,this.isOpened=!1,this.input=s(t),this.input.setAttribute("autocomplete","off"),this.input.setAttribute("aria-expanded","false"),this.input.setAttribute("aria-owns","awesomplete_list_"+this.count),this.input.setAttribute("role","combobox"),this.options=i=i||{},function(t,e,i){for(var n in e){var s=e[n],r=t.input.getAttribute("data-"+n.toLowerCase());t[n]="number"==typeof s?parseInt(r):!1===s?null!==r:s instanceof Function?null:r,t[n]||0===t[n]||(t[n]=n in i?i[n]:s)}}(this,{minChars:2,maxItems:10,autoFirst:!1,data:e.DATA,filter:e.FILTER_CONTAINS,sort:!1!==i.sort&&e.SORT_BYLENGTH,container:e.CONTAINER,item:e.ITEM,replace:e.REPLACE,tabSelect:!1},i),this.index=-1,this.container=this.container(t),this.ul=s.create("ul",{hidden:"hidden",role:"listbox",id:"awesomplete_list_"+this.count,inside:this.container}),this.status=s.create("span",{className:"visually-hidden",role:"status","aria-live":"assertive","aria-atomic":!0,inside:this.container,textContent:0!=this.minChars?"Type "+this.minChars+" or more characters for results.":"Begin typing for results."}),this._events={input:{input:this.evaluate.bind(this),blur:this.close.bind(this,{reason:"blur"}),keydown:function(t){var e=t.keyCode;n.opened&&(13===e&&n.selected?(t.preventDefault(),n.select()):9===e&&n.selected&&n.tabSelect?n.select():27===e?n.close({reason:"esc"}):38!==e&&40!==e||(t.preventDefault(),n[38===e?"previous":"next"]()))}},form:{submit:this.close.bind(this,{reason:"submit"})},ul:{mousedown:function(t){t.preventDefault()},click:function(t){var e=t.target;if(e!==this){for(;e&&!/li/i.test(e.nodeName);)e=e.parentNode;e&&0===t.button&&(t.preventDefault(),n.select(e,t.target))}}}},s.bind(this.input,this._events.input),s.bind(this.input.form,this._events.form),s.bind(this.ul,this._events.ul),this.input.hasAttribute("list")?(this.list="#"+this.input.getAttribute("list"),this.input.removeAttribute("list")):this.list=this.input.getAttribute("data-list")||i.list||[],e.all.push(this)};function i(t){var e=Array.isArray(t)?{label:t[0],value:t[1]}:"object"==typeof t&&"label"in t&&"value"in t?t:{label:t,value:t};this.label=e.label||e.value,this.value=e.value}e.prototype={set list(t){if(Array.isArray(t))this._list=t;else if("string"==typeof t&&t.indexOf(",")>-1)this._list=t.split(/\s*,\s*/);else if((t=s(t))&&t.children){var e=[];n.apply(t.children).forEach((function(t){if(!t.disabled){var i=t.textContent.trim(),n=t.value||i,s=t.label||i;""!==n&&e.push({label:s,value:n})}})),this._list=e}document.activeElement===this.input&&this.evaluate()},get selected(){return this.index>-1},get opened(){return this.isOpened},close:function(t){this.opened&&(this.input.setAttribute("aria-expanded","false"),this.ul.setAttribute("hidden",""),this.isOpened=!1,this.index=-1,this.status.setAttribute("hidden",""),s.fire(this.input,"awesomplete-close",t||{}))},open:function(){this.input.setAttribute("aria-expanded","true"),this.ul.removeAttribute("hidden"),this.isOpened=!0,this.status.removeAttribute("hidden"),this.autoFirst&&-1===this.index&&this.goto(0),s.fire(this.input,"awesomplete-open")},destroy:function(){if(s.unbind(this.input,this._events.input),s.unbind(this.input.form,this._events.form),!this.options.container){var t=this.container.parentNode;t.insertBefore(this.input,this.container),t.removeChild(this.container)}this.input.removeAttribute("autocomplete"),this.input.removeAttribute("aria-autocomplete");var i=e.all.indexOf(this);-1!==i&&e.all.splice(i,1)},next:function(){var t=this.ul.children.length;this.goto(this.index<t-1?this.index+1:t?0:-1)},previous:function(){var t=this.ul.children.length,e=this.index-1;this.goto(this.selected&&-1!==e?e:t-1)},goto:function(t){var e=this.ul.children;this.selected&&e[this.index].setAttribute("aria-selected","false"),this.index=t,t>-1&&e.length>0&&(e[t].setAttribute("aria-selected","true"),this.status.textContent=e[t].textContent+", list item "+(t+1)+" of "+e.length,this.input.setAttribute("aria-activedescendant",this.ul.id+"_item_"+this.index),this.ul.scrollTop=e[t].offsetTop-this.ul.clientHeight+e[t].clientHeight,s.fire(this.input,"awesomplete-highlight",{text:this.suggestions[this.index]}))},select:function(t,e){if(t?this.index=s.siblingIndex(t):t=this.ul.children[this.index],t){var i=this.suggestions[this.index];s.fire(this.input,"awesomplete-select",{text:i,origin:e||t})&&(this.replace(i),this.close({reason:"select"}),s.fire(this.input,"awesomplete-selectcomplete",{text:i}))}},evaluate:function(){var t=this,e=this.input.value;e.length>=this.minChars&&this._list&&this._list.length>0?(this.index=-1,this.ul.innerHTML="",this.suggestions=this._list.map((function(n){return new i(t.data(n,e))})).filter((function(i){return t.filter(i,e)})),!1!==this.sort&&(this.suggestions=this.suggestions.sort(this.sort)),this.suggestions=this.suggestions.slice(0,this.maxItems),this.suggestions.forEach((function(i,n){t.ul.appendChild(t.item(i,e,n))})),0===this.ul.children.length?(this.status.textContent="No results found",this.close({reason:"nomatches"})):(this.open(),this.status.textContent=this.ul.children.length+" results found")):(this.close({reason:"nomatches"}),this.status.textContent="No results found")}},e.all=[],e.FILTER_CONTAINS=function(t,e){return RegExp(s.regExpEscape(e.trim()),"i").test(t)},e.FILTER_STARTSWITH=function(t,e){return RegExp("^"+s.regExpEscape(e.trim()),"i").test(t)},e.SORT_BYLENGTH=function(t,e){return t.length!==e.length?t.length-e.length:t<e?-1:1},e.CONTAINER=function(t){return s.create("div",{className:"awesomplete",around:t})},e.ITEM=function(t,e,i){var n=""===e.trim()?t:t.replace(RegExp(s.regExpEscape(e.trim()),"gi"),"<mark>$&</mark>");return s.create("li",{innerHTML:n,role:"option","aria-selected":"false",id:"awesomplete_list_"+this.count+"_item_"+i})},e.REPLACE=function(t){this.input.value=t.value},e.DATA=function(t){return t},Object.defineProperty(i.prototype=Object.create(String.prototype),"length",{get:function(){return this.label.length}}),i.prototype.toString=i.prototype.valueOf=function(){return""+this.label};var n=Array.prototype.slice;function s(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function r(t,e){return n.call((e||document).querySelectorAll(t))}function o(){r("input.awesomplete").forEach((function(t){new e(t)}))}return s.create=function(t,e){var i=document.createElement(t);for(var n in e){var r=e[n];if("inside"===n)s(r).appendChild(i);else if("around"===n){var o=s(r);o.parentNode.insertBefore(i,o),i.appendChild(o),null!=o.getAttribute("autofocus")&&o.focus()}else n in i?i[n]=r:i.setAttribute(n,r)}return i},s.bind=function(t,e){if(t)for(var i in e){var n=e[i];i.split(/\s+/).forEach((function(e){t.addEventListener(e,n)}))}},s.unbind=function(t,e){if(t)for(var i in e){var n=e[i];i.split(/\s+/).forEach((function(e){t.removeEventListener(e,n)}))}},s.fire=function(t,e,i){var n=document.createEvent("HTMLEvents");for(var s in n.initEvent(e,!0,!0),i)n[s]=i[s];return t.dispatchEvent(n)},s.regExpEscape=function(t){return t.replace(/[-\\^$*+?.()|[\]{}]/g,"\\$&")},s.siblingIndex=function(t){for(var e=0;t=t.previousElementSibling;e++);return e},"undefined"!=typeof self&&(self.Awesomplete=e),"undefined"!=typeof Document&&("loading"!==document.readyState?o():document.addEventListener("DOMContentLoaded",o)),e.$=s,e.$$=r,t.exports&&(t.exports=e),e}()}).call(this,i(6)(t))},6:function(t,e){t.exports=function(t){if(!t.webpackPolyfill){var e=Object.create(t);e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),Object.defineProperty(e,"exports",{enumerable:!0}),e.webpackPolyfill=1}return e}}}]);
\ No newline at end of file
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["autocomplete"],{
/***/ "./node_modules/webpack/buildin/harmony-module.js":
/*!*******************************************!*\
!*** (webpack)/buildin/harmony-module.js ***!
\*******************************************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("module.exports = function(originalModule) {\n\tif (!originalModule.webpackPolyfill) {\n\t\tvar module = Object.create(originalModule);\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"exports\", {\n\t\t\tenumerable: true\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n\n\n//# sourceURL=webpack:///(webpack)/buildin/harmony-module.js?");
/***/ }),
/***/ "./wp-content/themes/biuro/js/components/autocomplete/autocomplete.js":
/*!****************************************************************************!*\
!*** ./wp-content/themes/biuro/js/components/autocomplete/autocomplete.js ***!
\****************************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _vendor_awesomplete__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vendor/awesomplete */ \"./wp-content/themes/biuro/js/components/autocomplete/vendor/awesomplete.js\");\n\n\nconst lisp = str => {\n var symbols = {\n 'ą': 'a',\n 'č': 'c',\n 'ę': 'e',\n 'ė': 'e',\n 'į': 'i',\n 'š': 's',\n 'ų': 'u',\n 'ū': 'u',\n 'ž': 'z',\n 'ā': 'a',\n 'ē': 'e',\n 'ģ': 'g',\n 'ī': 'i',\n 'ķ': 'k',\n 'ļ': 'l',\n 'ņ': 'n',\n 'õ': 'o',\n 'ä': 'a',\n 'ö': 'o',\n 'ü': 'u'\n };\n str = str.trim();\n str = str.toLowerCase();\n str = str.replace(/[ąčęėįšųūžāēģīķļņõäöü]/g, s => {\n return symbols[s];\n });\n return str;\n};\n\nconst autocomplete = str => {\n const node = document.getElementById(str);\n const arrow = document.querySelector('.js-toggle--' + str);\n const clear = document.querySelector('.js-clear--' + str);\n let isOpen = false;\n let isClosed = false;\n\n const update = (langID, target, str, hidden) => {\n const type = target.id === 'search-city' ? 'query' : 'city';\n fetch('/wp-json/api/v1/options?langID=' + langID + '&str=' + str + '&type=' + type).then(t => t.json()).then(data => {\n if (!data || !data.length) {\n return;\n }\n\n const list = data.map(option => {\n return {\n label: option.name + ' (' + option.total + ')',\n value: option.name\n };\n });\n target.box.list = list;\n\n if (hidden) {\n target.box.evaluate();\n target.box.close();\n } else {\n target.focus();\n target.box.evaluate();\n }\n });\n };\n\n const updateOptions = node => {\n const target = node.id === 'search-city' ? document.getElementById('search-query') : document.getElementById('search-city');\n\n if (!target || target.value && node.value) {\n return;\n }\n\n if (!target.value && node.value) {\n update(node.dataset.id, target, node.value, true);\n } else if (!node.value) {\n update(node.dataset.id, node, target.value);\n\n if (!target.value) {\n update(node.dataset.id, target, target.value, true);\n }\n }\n };\n\n const toggle = (status, delay = 0) => {\n setTimeout(() => {\n isOpen = status;\n }, delay);\n\n if (arrow) {\n arrow.classList.toggle('is-open', status);\n }\n };\n\n if (!node) {\n return;\n }\n\n const box = new _vendor_awesomplete__WEBPACK_IMPORTED_MODULE_0__[\"default\"](node, {\n minChars: 0,\n maxItems: 1000,\n sort: false,\n filter: function (text, input) {\n return lisp(text).indexOf(lisp(input)) !== -1;\n }\n });\n node.addEventListener('input', () => {\n if (clear) {\n clear.classList.toggle('u-hidden', !node.value);\n }\n\n if (arrow) {\n arrow.classList.toggle('u-hidden', !!node.value);\n }\n });\n node.addEventListener('focus', () => {\n if (!isOpen && (box.ul.childNodes.length === 0 || box.ul.hasAttribute('hidden'))) {\n toggle(true);\n box.evaluate();\n } else {\n toggle(false);\n box.close();\n node.blur();\n }\n });\n node.addEventListener('blur', () => {\n const suggestion = Array.isArray(box.suggestions) && box.suggestions.length === 1 ? box.suggestions[0] : null;\n\n if (!suggestion) {\n return;\n }\n\n if (lisp(node.value) === lisp(suggestion.value)) {\n node.value = suggestion.value;\n }\n });\n node.addEventListener('awesomplete-selectcomplete', () => {\n node.blur();\n updateOptions(node);\n\n if (clear) {\n clear.classList.remove('u-hidden');\n }\n\n if (arrow) {\n arrow.classList.add('u-hidden');\n }\n });\n node.addEventListener('awesomplete-close', () => {\n toggle(false, 150);\n });\n\n if (arrow) {\n arrow.addEventListener('click', e => {\n if (!isOpen) {\n node.focus();\n } else {\n box.close();\n }\n });\n }\n\n if (clear) {\n clear.addEventListener('click', () => {\n node.value = '';\n updateOptions(node);\n\n if (clear) {\n clear.classList.add('u-hidden');\n }\n\n if (arrow) {\n arrow.classList.remove('u-hidden');\n }\n });\n }\n\n node.box = box;\n};\n\nconst setCityAwesomplete = (node, cityID) => {\n if (!node || !cityID) {\n return;\n }\n\n const nodeBox = new _vendor_awesomplete__WEBPACK_IMPORTED_MODULE_0__[\"default\"](node, {\n minChars: 0,\n maxItems: 1000,\n sort: false,\n filter: function (text, input) {\n return lisp(text).indexOf(lisp(input)) !== -1;\n },\n replace: function (suggestion) {\n this.input.value = suggestion.label;\n\n if (cityID) {\n cityID.value = suggestion.value;\n }\n }\n });\n node.addEventListener('focus', () => {\n nodeBox.evaluate();\n });\n node.addEventListener('blur', () => {\n const suggestion = Array.isArray(nodeBox.suggestions) && nodeBox.suggestions.length === 1 ? nodeBox.suggestions[0] : null;\n\n if (!suggestion) {\n return;\n }\n\n if (lisp(node.value) === lisp(suggestion.label)) {\n node.value = suggestion.label;\n\n if (cityID) {\n cityID.value = suggestion.value;\n }\n }\n });\n};\n\nconst setCityAwesompletes = () => {\n setCityAwesomplete(document.getElementById('form-city'), document.getElementById('form-city-id'));\n setCityAwesomplete(document.getElementById('recommend-form-city'), document.getElementById('recommend-form-city-id'));\n};\n\nconst inititateAutocomplete = () => {\n const search = document.getElementById('search');\n const city = document.getElementById('search-city');\n const query = document.getElementById('search-query');\n\n if (city) {\n autocomplete('search-city');\n }\n\n if (query) {\n autocomplete('search-query');\n }\n\n if (search && city && query) {\n search.addEventListener('submit', e => {\n if (!city.value && !query.value) {\n city.focus();\n e.preventDefault();\n }\n }, false);\n }\n\n setCityAwesompletes();\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (inititateAutocomplete);\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/autocomplete/autocomplete.js?");
/***/ }),
/***/ "./wp-content/themes/biuro/js/components/autocomplete/vendor/awesomplete.js":
/*!**********************************************************************************!*\
!*** ./wp-content/themes/biuro/js/components/autocomplete/vendor/awesomplete.js ***!
\**********************************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(module) {/**\n * Simple, lightweight, usable local autocomplete library for modern browsers\n * Because there weren’t enough autocomplete scripts in the world? Because I’m completely insane and have NIH syndrome? Probably both. :P\n * @author Lea Verou http://leaverou.github.io/awesomplete\n * MIT license\n */\n/* harmony default export */ __webpack_exports__[\"default\"] = ((function () {\n var _ = function (input, o) {\n var me = this; // Keep track of number of instances for unique IDs\n\n _.count = (_.count || 0) + 1;\n this.count = _.count; // Setup\n\n this.isOpened = false;\n this.input = $(input);\n this.input.setAttribute(\"autocomplete\", \"off\");\n this.input.setAttribute(\"aria-expanded\", \"false\");\n this.input.setAttribute(\"aria-owns\", \"awesomplete_list_\" + this.count);\n this.input.setAttribute(\"role\", \"combobox\"); // store constructor options in case we need to distinguish\n // between default and customized behavior later on\n\n this.options = o = o || {};\n configure(this, {\n minChars: 2,\n maxItems: 10,\n autoFirst: false,\n data: _.DATA,\n filter: _.FILTER_CONTAINS,\n sort: o.sort === false ? false : _.SORT_BYLENGTH,\n container: _.CONTAINER,\n item: _.ITEM,\n replace: _.REPLACE,\n tabSelect: false\n }, o);\n this.index = -1; // Create necessary elements\n\n this.container = this.container(input);\n this.ul = $.create(\"ul\", {\n hidden: \"hidden\",\n role: \"listbox\",\n id: \"awesomplete_list_\" + this.count,\n inside: this.container\n });\n this.status = $.create(\"span\", {\n className: \"visually-hidden\",\n role: \"status\",\n \"aria-live\": \"assertive\",\n \"aria-atomic\": true,\n inside: this.container,\n textContent: this.minChars != 0 ? \"Type \" + this.minChars + \" or more characters for results.\" : \"Begin typing for results.\"\n }); // Bind events\n\n this._events = {\n input: {\n \"input\": this.evaluate.bind(this),\n \"blur\": this.close.bind(this, {\n reason: \"blur\"\n }),\n \"keydown\": function (evt) {\n var c = evt.keyCode; // If the dropdown `ul` is in view, then act on keydown for the following keys:\n // Enter / Esc / Up / Down\n\n if (me.opened) {\n if (c === 13 && me.selected) {\n // Enter\n evt.preventDefault();\n me.select();\n } else if (c === 9 && me.selected && me.tabSelect) {\n me.select();\n } else if (c === 27) {\n // Esc\n me.close({\n reason: \"esc\"\n });\n } else if (c === 38 || c === 40) {\n // Down/Up arrow\n evt.preventDefault();\n me[c === 38 ? \"previous\" : \"next\"]();\n }\n }\n }\n },\n form: {\n \"submit\": this.close.bind(this, {\n reason: \"submit\"\n })\n },\n ul: {\n // Prevent the default mousedowm, which ensures the input is not blurred.\n // The actual selection will happen on click. This also ensures dragging the\n // cursor away from the list item will cancel the selection\n \"mousedown\": function (evt) {\n evt.preventDefault();\n },\n // The click event is fired even if the corresponding mousedown event has called preventDefault\n \"click\": function (evt) {\n var li = evt.target;\n\n if (li !== this) {\n while (li && !/li/i.test(li.nodeName)) {\n li = li.parentNode;\n }\n\n if (li && evt.button === 0) {\n // Only select on left click\n evt.preventDefault();\n me.select(li, evt.target);\n }\n }\n }\n }\n };\n $.bind(this.input, this._events.input);\n $.bind(this.input.form, this._events.form);\n $.bind(this.ul, this._events.ul);\n\n if (this.input.hasAttribute(\"list\")) {\n this.list = \"#\" + this.input.getAttribute(\"list\");\n this.input.removeAttribute(\"list\");\n } else {\n this.list = this.input.getAttribute(\"data-list\") || o.list || [];\n }\n\n _.all.push(this);\n };\n\n _.prototype = {\n set list(list) {\n if (Array.isArray(list)) {\n this._list = list;\n } else if (typeof list === \"string\" && list.indexOf(\",\") > -1) {\n this._list = list.split(/\\s*,\\s*/);\n } else {\n // Element or CSS selector\n list = $(list);\n\n if (list && list.children) {\n var items = [];\n slice.apply(list.children).forEach(function (el) {\n if (!el.disabled) {\n var text = el.textContent.trim();\n var value = el.value || text;\n var label = el.label || text;\n\n if (value !== \"\") {\n items.push({\n label: label,\n value: value\n });\n }\n }\n });\n this._list = items;\n }\n }\n\n if (document.activeElement === this.input) {\n this.evaluate();\n }\n },\n\n get selected() {\n return this.index > -1;\n },\n\n get opened() {\n return this.isOpened;\n },\n\n close: function (o) {\n if (!this.opened) {\n return;\n }\n\n this.input.setAttribute(\"aria-expanded\", \"false\");\n this.ul.setAttribute(\"hidden\", \"\");\n this.isOpened = false;\n this.index = -1;\n this.status.setAttribute(\"hidden\", \"\");\n $.fire(this.input, \"awesomplete-close\", o || {});\n },\n open: function () {\n this.input.setAttribute(\"aria-expanded\", \"true\");\n this.ul.removeAttribute(\"hidden\");\n this.isOpened = true;\n this.status.removeAttribute(\"hidden\");\n\n if (this.autoFirst && this.index === -1) {\n this.goto(0);\n }\n\n $.fire(this.input, \"awesomplete-open\");\n },\n destroy: function () {\n //remove events from the input and its form\n $.unbind(this.input, this._events.input);\n $.unbind(this.input.form, this._events.form); // cleanup container if it was created by Awesomplete but leave it alone otherwise\n\n if (!this.options.container) {\n //move the input out of the awesomplete container and remove the container and its children\n var parentNode = this.container.parentNode;\n parentNode.insertBefore(this.input, this.container);\n parentNode.removeChild(this.container);\n } //remove autocomplete and aria-autocomplete attributes\n\n\n this.input.removeAttribute(\"autocomplete\");\n this.input.removeAttribute(\"aria-autocomplete\"); //remove this awesomeplete instance from the global array of instances\n\n var indexOfAwesomplete = _.all.indexOf(this);\n\n if (indexOfAwesomplete !== -1) {\n _.all.splice(indexOfAwesomplete, 1);\n }\n },\n next: function () {\n var count = this.ul.children.length;\n this.goto(this.index < count - 1 ? this.index + 1 : count ? 0 : -1);\n },\n previous: function () {\n var count = this.ul.children.length;\n var pos = this.index - 1;\n this.goto(this.selected && pos !== -1 ? pos : count - 1);\n },\n // Should not be used, highlights specific item without any checks!\n goto: function (i) {\n var lis = this.ul.children;\n\n if (this.selected) {\n lis[this.index].setAttribute(\"aria-selected\", \"false\");\n }\n\n this.index = i;\n\n if (i > -1 && lis.length > 0) {\n lis[i].setAttribute(\"aria-selected\", \"true\");\n this.status.textContent = lis[i].textContent + \", list item \" + (i + 1) + \" of \" + lis.length;\n this.input.setAttribute(\"aria-activedescendant\", this.ul.id + \"_item_\" + this.index); // scroll to highlighted element in case parent's height is fixed\n\n this.ul.scrollTop = lis[i].offsetTop - this.ul.clientHeight + lis[i].clientHeight;\n $.fire(this.input, \"awesomplete-highlight\", {\n text: this.suggestions[this.index]\n });\n }\n },\n select: function (selected, origin) {\n if (selected) {\n this.index = $.siblingIndex(selected);\n } else {\n selected = this.ul.children[this.index];\n }\n\n if (selected) {\n var suggestion = this.suggestions[this.index];\n var allowed = $.fire(this.input, \"awesomplete-select\", {\n text: suggestion,\n origin: origin || selected\n });\n\n if (allowed) {\n this.replace(suggestion);\n this.close({\n reason: \"select\"\n });\n $.fire(this.input, \"awesomplete-selectcomplete\", {\n text: suggestion\n });\n }\n }\n },\n evaluate: function () {\n var me = this;\n var value = this.input.value;\n\n if (value.length >= this.minChars && this._list && this._list.length > 0) {\n this.index = -1; // Populate list with options that match\n\n this.ul.innerHTML = \"\";\n this.suggestions = this._list.map(function (item) {\n return new Suggestion(me.data(item, value));\n }).filter(function (item) {\n return me.filter(item, value);\n });\n\n if (this.sort !== false) {\n this.suggestions = this.suggestions.sort(this.sort);\n }\n\n this.suggestions = this.suggestions.slice(0, this.maxItems);\n this.suggestions.forEach(function (text, index) {\n me.ul.appendChild(me.item(text, value, index));\n });\n\n if (this.ul.children.length === 0) {\n this.status.textContent = \"No results found\";\n this.close({\n reason: \"nomatches\"\n });\n } else {\n this.open();\n this.status.textContent = this.ul.children.length + \" results found\";\n }\n } else {\n this.close({\n reason: \"nomatches\"\n });\n this.status.textContent = \"No results found\";\n }\n }\n }; // Static methods/properties\n\n _.all = [];\n\n _.FILTER_CONTAINS = function (text, input) {\n return RegExp($.regExpEscape(input.trim()), \"i\").test(text);\n };\n\n _.FILTER_STARTSWITH = function (text, input) {\n return RegExp(\"^\" + $.regExpEscape(input.trim()), \"i\").test(text);\n };\n\n _.SORT_BYLENGTH = function (a, b) {\n if (a.length !== b.length) {\n return a.length - b.length;\n }\n\n return a < b ? -1 : 1;\n };\n\n _.CONTAINER = function (input) {\n return $.create(\"div\", {\n className: \"awesomplete\",\n around: input\n });\n };\n\n _.ITEM = function (text, input, item_id) {\n var html = input.trim() === \"\" ? text : text.replace(RegExp($.regExpEscape(input.trim()), \"gi\"), \"<mark>$&</mark>\");\n return $.create(\"li\", {\n innerHTML: html,\n \"role\": \"option\",\n \"aria-selected\": \"false\",\n \"id\": \"awesomplete_list_\" + this.count + \"_item_\" + item_id\n });\n };\n\n _.REPLACE = function (text) {\n this.input.value = text.value;\n };\n\n _.DATA = function (item\n /*, input*/\n ) {\n return item;\n }; // Private functions\n\n\n function Suggestion(data) {\n var o = Array.isArray(data) ? {\n label: data[0],\n value: data[1]\n } : typeof data === \"object\" && \"label\" in data && \"value\" in data ? data : {\n label: data,\n value: data\n };\n this.label = o.label || o.value;\n this.value = o.value;\n }\n\n Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), \"length\", {\n get: function () {\n return this.label.length;\n }\n });\n\n Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {\n return \"\" + this.label;\n };\n\n function configure(instance, properties, o) {\n for (var i in properties) {\n var initial = properties[i],\n attrValue = instance.input.getAttribute(\"data-\" + i.toLowerCase());\n\n if (typeof initial === \"number\") {\n instance[i] = parseInt(attrValue);\n } else if (initial === false) {\n // Boolean options must be false by default anyway\n instance[i] = attrValue !== null;\n } else if (initial instanceof Function) {\n instance[i] = null;\n } else {\n instance[i] = attrValue;\n }\n\n if (!instance[i] && instance[i] !== 0) {\n instance[i] = i in o ? o[i] : initial;\n }\n }\n } // Helpers\n\n\n var slice = Array.prototype.slice;\n\n function $(expr, con) {\n return typeof expr === \"string\" ? (con || document).querySelector(expr) : expr || null;\n }\n\n function $$(expr, con) {\n return slice.call((con || document).querySelectorAll(expr));\n }\n\n $.create = function (tag, o) {\n var element = document.createElement(tag);\n\n for (var i in o) {\n var val = o[i];\n\n if (i === \"inside\") {\n $(val).appendChild(element);\n } else if (i === \"around\") {\n var ref = $(val);\n ref.parentNode.insertBefore(element, ref);\n element.appendChild(ref);\n\n if (ref.getAttribute(\"autofocus\") != null) {\n ref.focus();\n }\n } else if (i in element) {\n element[i] = val;\n } else {\n element.setAttribute(i, val);\n }\n }\n\n return element;\n };\n\n $.bind = function (element, o) {\n if (element) {\n for (var event in o) {\n var callback = o[event];\n event.split(/\\s+/).forEach(function (event) {\n element.addEventListener(event, callback);\n });\n }\n }\n };\n\n $.unbind = function (element, o) {\n if (element) {\n for (var event in o) {\n var callback = o[event];\n event.split(/\\s+/).forEach(function (event) {\n element.removeEventListener(event, callback);\n });\n }\n }\n };\n\n $.fire = function (target, type, properties) {\n var evt = document.createEvent(\"HTMLEvents\");\n evt.initEvent(type, true, true);\n\n for (var j in properties) {\n evt[j] = properties[j];\n }\n\n return target.dispatchEvent(evt);\n };\n\n $.regExpEscape = function (s) {\n return s.replace(/[-\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\");\n };\n\n $.siblingIndex = function (el) {\n /* eslint-disable no-cond-assign */\n for (var i = 0; el = el.previousElementSibling; i++);\n\n return i;\n }; // Initialization\n\n\n function init() {\n $$(\"input.awesomplete\").forEach(function (input) {\n new _(input);\n });\n } // Make sure to export Awesomplete on self when in a browser\n\n\n if (typeof self !== \"undefined\") {\n self.Awesomplete = _;\n } // Are we in a browser? Check for Document constructor\n\n\n if (typeof Document !== \"undefined\") {\n // DOM already loaded?\n if (document.readyState !== \"loading\") {\n init();\n } else {\n // Wait for it\n document.addEventListener(\"DOMContentLoaded\", init);\n }\n }\n\n _.$ = $;\n _.$$ = $$; // Expose Awesomplete as a CJS module\n\n if ( true && module.exports) {\n module.exports = _;\n }\n\n return _;\n})());\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../../../../../../node_modules/webpack/buildin/harmony-module.js */ \"./node_modules/webpack/buildin/harmony-module.js\")(module)))\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/autocomplete/vendor/awesomplete.js?");
/***/ })
}]);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{12:function(e,o,t){"use strict";t.r(o);var n=t(0);let c=!0;function a(){const e=document.querySelector("#copy-tooltip");e&&(e.style.opacity=1,setTimeout(()=>{e.style.opacity=0},3e3))}function i(e){if(!navigator.clipboard)return function(e){var o=document.createElement("textarea");o.className="u-hidden",o.value=e,document.querySelector(".c-share").appendChild(o),o.focus(),o.select();try{var t=document.execCommand("copy")?"successful":"unsuccessful";console.log("Fallback: Copying text command was "+t)}catch(e){console.error("Fallback: Oops, unable to copy",e)}document.body.removeChild(o)}(e),void a();navigator.clipboard.writeText(e).then((function(){a()}),(function(e){console.error("Async: Could not copy text: ",e)}))}window.onfocus=function(){c=!0},window.onblur=function(){c=!1};o.default=()=>{document.querySelector(".js-copy-to-clipboard")&&document.querySelector(".js-copy-to-clipboard").addEventListener("click",e=>{e.preventDefault(),i(window.location.origin+window.location.pathname+"?utm_source=copy_share_button_job_page ")});const e=document.querySelector(".js-share-messenger");e&&e.addEventListener("click",e=>{e.preventDefault();const o=e.currentTarget;window.location.href="fb-messenger://share/?link="+encodeURIComponent(window.location.origin+window.location.pathname+"?utm_source=messenger_share_button_job_page&app_id="+o.dataset.id),setTimeout(()=>{!document.hidden&&c&&(window.location.href=o.href)},100)});const o=document.querySelector(".js-share-whatsapp");o&&o.addEventListener("click",e=>{e.preventDefault();const o=e.currentTarget;window.location.href="whatsapp://send?text="+o.dataset.text,setTimeout(()=>{!document.hidden&&c&&window.open(o.href,"_blank")},100)});const t=document.querySelector(".js-biuro-facebook");t&&setTimeout(()=>{!async function(e){Object(n.a)("https://connect.facebook.net/en_US/sdk.js").then(()=>{window.FB&&window.FB.init({appId:e,version:"v3.3",status:!0,xfbml:!0})})}(t.dataset.id)},1500)}}}]);
\ No newline at end of file
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["job-share"],{
/***/ "./wp-content/themes/biuro/js/components/job-share/job-share.js":
/*!**********************************************************************!*\
!*** ./wp-content/themes/biuro/js/components/job-share/job-share.js ***!
\**********************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _utils_load_js_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../utils/load-js.js */ \"./wp-content/themes/biuro/js/utils/load-js.js\");\n\n\nasync function inititateFacebook(ID) {\n Object(_utils_load_js_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])('https://connect.facebook.net/en_US/sdk.js').then(() => {\n if (!window.FB) {\n return;\n }\n\n window.FB.init({\n appId: ID,\n version: 'v3.3',\n status: true,\n xfbml: true\n });\n });\n}\n\nlet isPageActive = true;\n\nwindow.onfocus = function () {\n isPageActive = true;\n};\n\nwindow.onblur = function () {\n isPageActive = false;\n};\n\nfunction fallbackCopyTextToClipboard(text) {\n var textArea = document.createElement('textarea');\n textArea.className = 'u-hidden';\n textArea.value = text;\n document.querySelector('.c-share').appendChild(textArea);\n textArea.focus();\n textArea.select();\n\n try {\n var successful = document.execCommand('copy');\n var msg = successful ? 'successful' : 'unsuccessful';\n console.log('Fallback: Copying text command was ' + msg);\n } catch (err) {\n console.error('Fallback: Oops, unable to copy', err);\n }\n\n document.body.removeChild(textArea);\n}\n\nfunction showCopyTooltip() {\n const tooltip = document.querySelector('#copy-tooltip');\n\n if (tooltip) {\n tooltip.style.opacity = 1;\n setTimeout(() => {\n tooltip.style.opacity = 0;\n }, 3000);\n }\n}\n\nfunction copyTextToClipboard(text) {\n if (!navigator.clipboard) {\n fallbackCopyTextToClipboard(text);\n showCopyTooltip();\n return;\n }\n\n navigator.clipboard.writeText(text).then(function () {\n showCopyTooltip();\n }, function (err) {\n console.error('Async: Could not copy text: ', err);\n });\n}\n\nconst inititateJobShare = () => {\n if (document.querySelector('.js-copy-to-clipboard')) {\n document.querySelector('.js-copy-to-clipboard').addEventListener('click', e => {\n e.preventDefault();\n copyTextToClipboard(window.location.origin + window.location.pathname + '?utm_source=copy_share_button_job_page ');\n });\n }\n\n const messenger = document.querySelector('.js-share-messenger');\n\n if (messenger) {\n messenger.addEventListener('click', e => {\n e.preventDefault();\n const target = e.currentTarget;\n window.location.href = 'fb-messenger://share/?link=' + encodeURIComponent(window.location.origin + window.location.pathname + '?utm_source=messenger_share_button_job_page&app_id=' + target.dataset.id);\n setTimeout(() => {\n if (document.hidden || !isPageActive) {\n return;\n }\n\n window.location.href = target.href;\n }, 100);\n });\n }\n\n const whatsapp = document.querySelector('.js-share-whatsapp');\n\n if (whatsapp) {\n whatsapp.addEventListener('click', e => {\n e.preventDefault();\n const target = e.currentTarget;\n window.location.href = 'whatsapp://send?text=' + target.dataset.text;\n setTimeout(() => {\n if (document.hidden || !isPageActive) {\n return;\n }\n\n window.open(target.href, '_blank');\n }, 100);\n });\n }\n\n const facebook = document.querySelector('.js-biuro-facebook');\n\n if (facebook) {\n setTimeout(() => {\n inititateFacebook(facebook.dataset.id);\n }, 1500);\n }\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (inititateJobShare);\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/job-share/job-share.js?");
/***/ })
}]);
\ No newline at end of file
(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{11:function(e,t,n){"use strict";n.r(t);var o,i=n(0);function s(e,t){const n=function(){function e(e,t,n="top"){this.position=e;var o=document.createElement("div");o.innerHTML=t||"",o.classList.add("popup-bubble"),o.classList.add("popup-bubble--"+n);var i=document.createElement("div");i.classList.add("popup-bubble-anchor"),i.appendChild(o),this.containerDiv=document.createElement("div"),this.containerDiv.classList.add("popup-container"),this.containerDiv.appendChild(i),window.google.maps.OverlayView.preventMapHitsAndGesturesFrom(this.containerDiv)}return e.prototype=Object.create(window.google.maps.OverlayView.prototype),e.prototype.onAdd=function(){this.getPanes().floatPane.appendChild(this.containerDiv)},e.prototype.onRemove=function(){this.containerDiv.parentElement&&this.containerDiv.parentElement.removeChild(this.containerDiv)},e.prototype.draw=function(){var e=this.getProjection().fromLatLngToDivPixel(this.position),t=Math.abs(e.x)<4e3&&Math.abs(e.y)<4e3?"block":"none";"block"===t&&(this.containerDiv.style.left=e.x+"px",this.containerDiv.style.top=e.y+"px"),this.containerDiv.style.display!==t&&(this.containerDiv.style.display=t)},e}(),o=new window.google.maps.LatLngBounds;let i;for(var s=0;s<t.length;s++){const a=t[s],l=new window.google.maps.LatLng(a.lat,a.lng);i=new n(l,a.title,a.pos),i.setMap(e),o.extend(l)}e.fitBounds(o)}function a(e,t,n){for(var i=new window.google.maps.LatLngBounds,s=0;s<t.length;s++){const l=t[s],d=new window.google.maps.LatLng(l.lat,l.lng);var a=new window.google.maps.Marker({position:d,map:e,icon:"/wp-content/themes/biuro/i/ico--map-pin.svg",title:l.title||""});o&&o.close(),i.extend(d),l.content&&(a.content=l.content,window.google.maps.event.addListener(a,"click",(function(){o&&o.close(),(o=new window.google.maps.InfoWindow({content:this.content})).open(e,this)}))),n&&(window.innerWidth<960&&window.scrollTo(0,0),new google.maps.event.trigger(a,"click"))}e.fitBounds(i),window.innerWidth>1020?e.panBy(250,0):window.innerWidth>959&&e.panBy(180,0)}function l(e){var t=new window.google.maps.Map(e,{}),n=new window.google.maps.StyledMapType([{featureType:"all",elementType:"all",stylers:[{saturation:-92},{lightness:-8},{hue:"#004ed4"}]},{featureType:"water",elementType:"all",stylers:[{saturation:-95},{lightness:-25},{hue:"#004ed4"}]}],{name:"Biuro"});return t.mapTypes.set("biuro",n),t.setMapTypeId("biuro"),window.google.maps.event.addListenerOnce(t,"bounds_changed",(function(){this.getZoom()>15&&this.setZoom(14)})),t}t.default=()=>{const e=document.getElementById("js-map--divisions");e&&fetch("/wp-json/api/v1/divisions?langID="+e.dataset.id).then(e=>e.json()).then(t=>{!function(e,t){Object(i.a)("https://maps.googleapis.com/maps/api/js?key=AIzaSyBQjPQnLGLeICbpTTu8kLjVRrLUYYCTS2M").then(()=>{window.google&&setTimeout(()=>{var n=l(e);let o=[];Object.keys(t).forEach(e=>{const n=t[e];"city"===e.substr(0,4)&&(o=o.concat(n))}),document.querySelectorAll(".js-division").forEach(e=>{e.addEventListener("click",()=>{const i=e&&e.dataset.id?e.dataset.id:"";t[i]?a(n,t[i].filter(e=>e.lat&&e.lng),!0):a(n,o.filter(e=>e.lat&&e.lng))})}),a(n,o.filter(e=>e.lat&&e.lng))},50)})}(e,t)});const t=document.getElementById("js-map--cities");t&&fetch("/wp-content/themes/biuro/json/"+t.dataset.source+".json").then(e=>e.json()).then(e=>{!function e(t,n){if(window.google){var o=l(t);s(o,n),window.innerWidth>1020?o.panBy(-230,0):window.innerWidth>959&&o.panBy(-150,0)}else setTimeout(()=>{e(t,n)},250)}(t,e)});const n=document.getElementById("js-map--regions");n&&function e(t){if(!window.google)return void setTimeout(()=>{e(t)},250);a(l(t),[{title:"Vilnius",lat:54.687157,lng:25.279652},{title:"Rīga",lat:56.946285,lng:24.105078},{title:"Tallinn",lat:59.436962,lng:24.753574}])}(n)}}}]);
\ No newline at end of file
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["map"],{
/***/ "./wp-content/themes/biuro/js/components/map/map.js":
/*!**********************************************************!*\
!*** ./wp-content/themes/biuro/js/components/map/map.js ***!
\**********************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _utils_load_js_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../utils/load-js.js */ \"./wp-content/themes/biuro/js/utils/load-js.js\");\n // https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/examples/overlay-popup\n\nfunction createPopupClass() {\n function Popup(position, city, pos = 'top') {\n this.position = position;\n var content = document.createElement('div');\n content.innerHTML = city || '';\n content.classList.add('popup-bubble');\n content.classList.add('popup-bubble--' + pos); // This zero-height div is positioned at the bottom of the bubble.\n\n var bubbleAnchor = document.createElement('div');\n bubbleAnchor.classList.add('popup-bubble-anchor');\n bubbleAnchor.appendChild(content); // This zero-height div is positioned at the bottom of the tip.\n\n this.containerDiv = document.createElement('div');\n this.containerDiv.classList.add('popup-container');\n this.containerDiv.appendChild(bubbleAnchor); // Optionally stop clicks, etc., from bubbling up to the map.\n\n window.google.maps.OverlayView.preventMapHitsAndGesturesFrom(this.containerDiv);\n } // ES5 magic to extend google.maps.OverlayView.\n\n\n Popup.prototype = Object.create(window.google.maps.OverlayView.prototype);\n /** Called when the popup is added to the map. */\n\n Popup.prototype.onAdd = function () {\n this.getPanes().floatPane.appendChild(this.containerDiv);\n };\n /** Called when the popup is removed from the map. */\n\n\n Popup.prototype.onRemove = function () {\n if (this.containerDiv.parentElement) {\n this.containerDiv.parentElement.removeChild(this.containerDiv);\n }\n };\n /** Called each frame when the popup needs to draw itself. */\n\n\n Popup.prototype.draw = function () {\n var divPosition = this.getProjection().fromLatLngToDivPixel(this.position); // Hide the popup when it is far out of view.\n\n var display = Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000 ? 'block' : 'none';\n\n if (display === 'block') {\n this.containerDiv.style.left = divPosition.x + 'px';\n this.containerDiv.style.top = divPosition.y + 'px';\n }\n\n if (this.containerDiv.style.display !== display) {\n this.containerDiv.style.display = display;\n }\n };\n\n return Popup;\n}\n\nvar info;\n\nfunction setCitiesMarkers(map, positions) {\n const Popup = createPopupClass();\n const bounds = new window.google.maps.LatLngBounds();\n let popup;\n\n for (var i = 0; i < positions.length; i++) {\n const position = positions[i];\n const pos = new window.google.maps.LatLng(position.lat, position.lng);\n popup = new Popup(pos, position.title, position.pos);\n popup.setMap(map);\n bounds.extend(pos);\n }\n\n map.fitBounds(bounds);\n}\n\nfunction setMarkers(map, positions, focus) {\n var bounds = new window.google.maps.LatLngBounds();\n\n for (var i = 0; i < positions.length; i++) {\n const position = positions[i];\n const pos = new window.google.maps.LatLng(position.lat, position.lng);\n var marker = new window.google.maps.Marker({\n position: pos,\n map: map,\n icon: '/wp-content/themes/biuro/i/ico--map-pin.svg',\n title: position.title || ''\n });\n\n if (info) {\n info.close();\n }\n\n bounds.extend(pos);\n\n if (position.content) {\n marker.content = position.content;\n window.google.maps.event.addListener(marker, 'click', function () {\n if (info) {\n info.close();\n }\n\n info = new window.google.maps.InfoWindow({\n content: this.content\n });\n info.open(map, this);\n });\n }\n\n if (focus) {\n if (window.innerWidth < 960) {\n window.scrollTo(0, 0);\n }\n\n new google.maps.event.trigger(marker, 'click');\n }\n }\n\n map.fitBounds(bounds);\n\n if (window.innerWidth > 1020) {\n map.panBy(250, 0);\n } else if (window.innerWidth > 959) {\n map.panBy(180, 0);\n }\n}\n\nfunction setGoogleMap(node) {\n const mapStyles = [{\n featureType: 'all',\n elementType: 'all',\n stylers: [{\n saturation: -92\n }, {\n lightness: -8\n }, {\n hue: '#004ed4'\n }]\n }, {\n featureType: 'water',\n elementType: 'all',\n stylers: [{\n saturation: -95\n }, {\n lightness: -25\n }, {\n hue: '#004ed4'\n }]\n }];\n var map = new window.google.maps.Map(node, {});\n var biuroMap = new window.google.maps.StyledMapType(mapStyles, {\n name: 'Biuro'\n });\n map.mapTypes.set('biuro', biuroMap);\n map.setMapTypeId('biuro');\n window.google.maps.event.addListenerOnce(map, 'bounds_changed', function () {\n if (this.getZoom() > 15) {\n this.setZoom(14);\n }\n });\n return map;\n}\n\nfunction initCitiesMap(node, cities) {\n if (!window.google) {\n setTimeout(() => {\n initCitiesMap(node, cities);\n }, 250);\n return;\n }\n\n var map = setGoogleMap(node);\n setCitiesMarkers(map, cities);\n\n if (window.innerWidth > 1020) {\n map.panBy(-230, 0);\n } else if (window.innerWidth > 959) {\n map.panBy(-150, 0);\n }\n}\n\nfunction initRegionsMap(node) {\n if (!window.google) {\n setTimeout(() => {\n initRegionsMap(node);\n }, 250);\n return;\n }\n\n var map = setGoogleMap(node);\n const regions = [{\n title: 'Vilnius',\n lat: 54.687157,\n lng: 25.279652\n }, {\n title: 'Rīga',\n lat: 56.946285,\n lng: 24.105078\n }, {\n title: 'Tallinn',\n lat: 59.436962,\n lng: 24.753574\n }];\n setMarkers(map, regions);\n}\n\nfunction initDivisionsMap(node, data) {\n Object(_utils_load_js_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])('https://maps.googleapis.com/maps/api/js?key=AIzaSyBQjPQnLGLeICbpTTu8kLjVRrLUYYCTS2M').then(() => {\n if (!window.google) {\n return;\n }\n\n setTimeout(() => {\n var map = setGoogleMap(node);\n let divisions = [];\n Object.keys(data).forEach(key => {\n const division = data[key];\n\n if (key.substr(0, 4) === 'city') {\n divisions = divisions.concat(division);\n }\n });\n document.querySelectorAll('.js-division').forEach(node => {\n node.addEventListener('click', () => {\n const ID = node && node.dataset.id ? node.dataset.id : '';\n\n if (data[ID]) {\n setMarkers(map, data[ID].filter(d => {\n return d.lat && d.lng;\n }), true);\n } else {\n setMarkers(map, divisions.filter(d => {\n return d.lat && d.lng;\n }));\n }\n });\n });\n setMarkers(map, divisions.filter(d => {\n return d.lat && d.lng;\n }));\n }, 50);\n });\n}\n\nconst inititateMap = () => {\n // <script src=\"https://maps.googleapis.com/maps/api/js?key=AIzaSyBQjPQnLGLeICbpTTu8kLjVRrLUYYCTS2M\" async defer></script>\n const division = document.getElementById('js-map--divisions');\n\n if (division) {\n fetch('/wp-json/api/v1/divisions?langID=' + division.dataset.id).then(t => t.json()).then(data => {\n initDivisionsMap(division, data);\n });\n }\n\n const city = document.getElementById('js-map--cities');\n\n if (city) {\n fetch('/wp-content/themes/biuro/json/' + city.dataset.source + '.json').then(t => t.json()).then(data => {\n initCitiesMap(city, data);\n });\n }\n\n const region = document.getElementById('js-map--regions');\n\n if (region) {\n initRegionsMap(region);\n }\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (inititateMap);\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/map/map.js?");
/***/ })
}]);
\ No newline at end of file
(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{13:function(e,p,t){"use strict";t.r(p);const o=(e,p,t)=>{const o={value:p,expiry:(new Date).getTime()+t};localStorage.setItem(e,JSON.stringify(o))},n=e=>{const p=localStorage.getItem(e);if(!p)return null;const t=JSON.parse(p);return(new Date).getTime()>t.expiry?(localStorage.removeItem(e),null):t.value},l=()=>{const e=document.getElementById("employer-popup");e&&!n("employer-popup")&&(o("employer-popup","expires",12096e5),window.dataLayer=window.dataLayer||[],e.style.display="block",window.dataLayer.push({event:"b2b_popup_show"}),e.querySelector(".js-popup--btn")&&e.querySelector(".js-popup--btn").addEventListener("click",e=>{window.dataLayer.push({event:"b2b_popup_navigate",label:"Recommend page"})}),e.querySelector(".js-popup--close")&&e.querySelector(".js-popup--close").addEventListener("click",p=>{p.preventDefault(),e.style.display="none"}))},a=e=>{const p=document.getElementById("employee-popup");p&&!n("employee-popup")&&e.clientY<50&&null==e.relatedTarget&&"select"!==e.target.nodeName.toLowerCase()&&(document.removeEventListener("mouseout",a),o("employee-popup","expires",12096e5),window.dataLayer=window.dataLayer||[],p.style.display="block",window.dataLayer.push({event:"b2c_popup_show"}),p.querySelector(".js-popup--btn")&&p.querySelector(".js-popup--btn").addEventListener("click",e=>{window.dataLayer.push({event:"b2c_popup_navigate",label:"Recommend page"})}),p.querySelector(".js-popup--close")&&p.querySelector(".js-popup--close").addEventListener("click",e=>{e.preventDefault(),p.style.display="none"}))};p.default=()=>{document.getElementById("employee-popup")&&!n("employee-popup")&&setTimeout(()=>{document.addEventListener("mouseout",a)},3e3),document.getElementById("employer-popup")&&!n("employer-popup")&&setTimeout(l,45e3)}}}]);
\ No newline at end of file
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["popup"],{
/***/ "./wp-content/themes/biuro/js/components/popup/popup.js":
/*!**************************************************************!*\
!*** ./wp-content/themes/biuro/js/components/popup/popup.js ***!
\**************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\nconst EMPLOYEE_DELAY = 3000; // 3 seconds\n\nconst EMPLOYEE_EXPIRY = 14 * 86400 * 1000; // 14 days\n\nconst EMPLOYER_DELAY = 45000; // 45 seconds\n\nconst EMPLOYER_EXPIRY = 14 * 86400 * 1000; // 14 days\n\nconst setExpirableItem = (key, value, ttl) => {\n const now = new Date(); // `item` is an object which contains the original value\n // as well as the time when it's supposed to expire\n\n const item = {\n value: value,\n expiry: now.getTime() + ttl\n };\n localStorage.setItem(key, JSON.stringify(item));\n};\n\nconst getExpirableItem = key => {\n const itemStr = localStorage.getItem(key); // if the item doesn't exist, return null\n\n if (!itemStr) {\n return null;\n }\n\n const item = JSON.parse(itemStr);\n const now = new Date(); // compare the expiry time of the item with the current time\n\n if (now.getTime() > item.expiry) {\n // If the item is expired, delete the item from storage\n // and return null\n localStorage.removeItem(key);\n return null;\n }\n\n return item.value;\n};\n\nconst showEmployerPopup = () => {\n const container = document.getElementById('employer-popup');\n\n if (!container || getExpirableItem('employer-popup')) {\n return;\n }\n\n setExpirableItem('employer-popup', 'expires', EMPLOYER_EXPIRY);\n window.dataLayer = window.dataLayer || [];\n container.style.display = 'block';\n window.dataLayer.push({\n event: 'b2b_popup_show'\n });\n\n if (container.querySelector('.js-popup--btn')) {\n container.querySelector('.js-popup--btn').addEventListener('click', e => {\n window.dataLayer.push({\n event: 'b2b_popup_navigate',\n label: 'Recommend page'\n });\n });\n }\n\n if (container.querySelector('.js-popup--close')) {\n container.querySelector('.js-popup--close').addEventListener('click', e => {\n e.preventDefault();\n container.style.display = 'none';\n });\n }\n};\n\nconst showEmployeePopup = e => {\n const container = document.getElementById('employee-popup');\n\n if (!container || getExpirableItem('employee-popup')) {\n return;\n }\n\n if (e.clientY < 50 && e.relatedTarget == null && e.target.nodeName.toLowerCase() !== 'select') {\n document.removeEventListener('mouseout', showEmployeePopup);\n setExpirableItem('employee-popup', 'expires', EMPLOYEE_EXPIRY);\n window.dataLayer = window.dataLayer || [];\n container.style.display = 'block';\n window.dataLayer.push({\n event: 'b2c_popup_show'\n });\n\n if (container.querySelector('.js-popup--btn')) {\n container.querySelector('.js-popup--btn').addEventListener('click', e => {\n window.dataLayer.push({\n event: 'b2c_popup_navigate',\n label: 'Recommend page'\n });\n });\n }\n\n if (container.querySelector('.js-popup--close')) {\n container.querySelector('.js-popup--close').addEventListener('click', e => {\n e.preventDefault();\n container.style.display = 'none';\n });\n }\n }\n};\n\nconst inititatePopup = () => {\n if (document.getElementById('employee-popup') && !getExpirableItem('employee-popup')) {\n setTimeout(() => {\n document.addEventListener('mouseout', showEmployeePopup);\n }, EMPLOYEE_DELAY);\n }\n\n if (document.getElementById('employer-popup') && !getExpirableItem('employer-popup')) {\n setTimeout(showEmployerPopup, EMPLOYER_DELAY);\n }\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (inititatePopup);\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/popup/popup.js?");
/***/ })
}]);
\ No newline at end of file
(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{8:function(t,e,r){"use strict";r.r(e);e.default=()=>{const t=document.querySelector(".c-tabs"),e=t.querySelector("ul"),r=e.querySelectorAll("a"),a=t.querySelectorAll("section"),i=t=>{t&&(window.location.hash=t,history.pushState?history.pushState(null,t):location.hash=t)},o=(t,e)=>{e.focus(),e.removeAttribute("tabindex"),e.setAttribute("aria-selected","true"),t.removeAttribute("aria-selected"),t.setAttribute("tabindex","-1");const i=Array.prototype.indexOf.call(r,e),o=Array.prototype.indexOf.call(r,t);a[o].hidden=!0,a[i].hidden=!1};e.setAttribute("role","tablist"),Array.prototype.forEach.call(r,(t,n)=>{t.setAttribute("role","tab"),t.setAttribute("id","tab"+(n+1)),t.setAttribute("tabindex","-1"),t.parentNode.setAttribute("role","presentation"),t.addEventListener("click",t=>{t.preventDefault();const r=e.querySelector("[aria-selected]");t.currentTarget!==r&&(i(t.currentTarget.dataset.hash),o(r,t.currentTarget))}),t.addEventListener("keydown",t=>{const e=Array.prototype.indexOf.call(r,t.currentTarget),l=37===t.which?e-1:39===t.which?e+1:40===t.which?"down":null;null!==l&&(t.preventDefault(),"down"===l?a[n].focus():r[l]&&(i(t.currentTarget.dataset.hash),o(t.currentTarget,r[l])))})}),Array.prototype.forEach.call(a,(t,e)=>{t.setAttribute("role","tabpanel"),t.setAttribute("tabindex","-1"),t.setAttribute("aria-labelledby",r[e].id),t.hidden=!0});let n=0;if(location.hash){const t=location.hash.replace("#","");a.forEach((e,r)=>{e.id===t&&(n=r)})}r[n].removeAttribute("tabindex"),r[n].setAttribute("aria-selected","true"),a[n].hidden=!1}}}]);
\ No newline at end of file
(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["tabs"],{
/***/ "./wp-content/themes/biuro/js/components/tabs/tabs.js":
/*!************************************************************!*\
!*** ./wp-content/themes/biuro/js/components/tabs/tabs.js ***!
\************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\nconst inititateTabs = () => {\n // Get relevant elements and collections\n const container = document.querySelector('.c-tabs');\n const tablist = container.querySelector('ul');\n const tabs = tablist.querySelectorAll('a');\n const panels = container.querySelectorAll('section');\n\n const updateHash = hash => {\n if (!hash) {\n return;\n }\n\n window.location.hash = hash;\n\n if (history.pushState) {\n history.pushState(null, hash);\n } else {\n location.hash = hash;\n }\n }; // The tab switching function\n\n\n const switchTab = (oldTab, newTab) => {\n newTab.focus(); // Make the active tab focusable by the user (Tab key)\n\n newTab.removeAttribute('tabindex'); // Set the selected state\n\n newTab.setAttribute('aria-selected', 'true');\n oldTab.removeAttribute('aria-selected');\n oldTab.setAttribute('tabindex', '-1'); // Get the indices of the new and old tabs to find the correct\n // tab panels to show and hide\n\n const index = Array.prototype.indexOf.call(tabs, newTab);\n const oldIndex = Array.prototype.indexOf.call(tabs, oldTab);\n panels[oldIndex].hidden = true;\n panels[index].hidden = false;\n }; // Add the tablist role to the first <ul> in the .tabbed container\n\n\n tablist.setAttribute('role', 'tablist'); // Add semantics are remove user focusability for each tab\n\n Array.prototype.forEach.call(tabs, (tab, i) => {\n tab.setAttribute('role', 'tab');\n tab.setAttribute('id', 'tab' + (i + 1));\n tab.setAttribute('tabindex', '-1');\n tab.parentNode.setAttribute('role', 'presentation'); // Handle clicking of tabs for mouse users\n\n tab.addEventListener('click', e => {\n e.preventDefault();\n const currentTab = tablist.querySelector('[aria-selected]');\n\n if (e.currentTarget !== currentTab) {\n updateHash(e.currentTarget.dataset.hash);\n switchTab(currentTab, e.currentTarget);\n }\n }); // Handle keydown events for keyboard users\n\n tab.addEventListener('keydown', e => {\n // Get the index of the current tab in the tabs node list\n const index = Array.prototype.indexOf.call(tabs, e.currentTarget); // Work out which key the user is pressing and\n // Calculate the new tab's index where appropriate\n\n const dir = e.which === 37 ? index - 1 : e.which === 39 ? index + 1 : e.which === 40 ? 'down' : null;\n\n if (dir !== null) {\n e.preventDefault(); // If the down key is pressed, move focus to the open panel,\n // otherwise switch to the adjacent tab\n\n if (dir === 'down') {\n panels[i].focus();\n } else if (tabs[dir]) {\n updateHash(e.currentTarget.dataset.hash);\n switchTab(e.currentTarget, tabs[dir]);\n }\n }\n });\n }); // Add tab panel semantics and hide them all\n\n Array.prototype.forEach.call(panels, (panel, i) => {\n panel.setAttribute('role', 'tabpanel');\n panel.setAttribute('tabindex', '-1');\n panel.setAttribute('aria-labelledby', tabs[i].id);\n panel.hidden = true;\n });\n let indx = 0;\n\n if (location.hash) {\n const ID = location.hash.replace('#', '');\n panels.forEach((panel, i) => {\n if (panel.id === ID) {\n indx = i;\n }\n });\n } // Initially activate the first tab and reveal the first tab panel\n\n\n tabs[indx].removeAttribute('tabindex');\n tabs[indx].setAttribute('aria-selected', 'true');\n panels[indx].hidden = false;\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (inititateTabs);\n\n//# sourceURL=webpack:///./wp-content/themes/biuro/js/components/tabs/tabs.js?");
/***/ })
}]);
\ No newline at end of file
!function(e){function t(t){for(var o,c,r=t[0],s=t[1],a=0,d=[];a<r.length;a++)c=r[a],Object.prototype.hasOwnProperty.call(n,c)&&n[c]&&d.push(n[c][0]),n[c]=0;for(o in s)Object.prototype.hasOwnProperty.call(s,o)&&(e[o]=s[o]);for(i&&i(t);d.length;)d.shift()()}var o={},n={4:0};function c(t){if(o[t])return o[t].exports;var n=o[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,c),n.l=!0,n.exports}c.e=function(e){var t=[],o=n[e];if(0!==o)if(o)t.push(o[2]);else{var r=new Promise((function(t,c){o=n[e]=[t,c]}));t.push(o[2]=r);var s,a=document.createElement("script");a.charset="utf-8",a.timeout=120,c.nc&&a.setAttribute("nonce",c.nc),a.src=function(e){return c.p+"wp-content/themes/biuro/js/components/"+({0:"accordion",1:"autocomplete",2:"feedback",3:"job-share",5:"map",6:"popup",7:"tabs"}[e]||e)+"-"+{0:"2f69296d",1:"df0794bc",2:"3d1a4d26",3:"cf7870c2",5:"c443fad5",6:"e893a8e4",7:"9adc476f"}[e]+".min.js"}(e);var i=new Error;s=function(t){a.onerror=a.onload=null,clearTimeout(d);var o=n[e];if(0!==o){if(o){var c=t&&("load"===t.type?"missing":t.type),r=t&&t.target&&t.target.src;i.message="Loading chunk "+e+" failed.\n("+c+": "+r+")",i.name="ChunkLoadError",i.type=c,i.request=r,o[1](i)}n[e]=void 0}};var d=setTimeout((function(){s({type:"timeout",target:a})}),12e4);a.onerror=a.onload=s,document.head.appendChild(a)}return Promise.all(t)},c.m=e,c.c=o,c.d=function(e,t,o){c.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},c.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.t=function(e,t){if(1&t&&(e=c(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(c.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)c.d(o,n,function(t){return e[t]}.bind(null,n));return o},c.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return c.d(t,"a",t),t},c.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},c.p="/",c.oe=function(e){throw console.error(e),e};var r=window.webpackJsonp=window.webpackJsonp||[],s=r.push.bind(r);r.push=t,r=r.slice();for(var a=0;a<r.length;a++)t(r[a]);var i=s;c(c.s=1)}([function(e,t,o){"use strict";function n(e){return new Promise((t,o)=>{const n=document.createElement("script");n.src=e,n.async=!0,n.onload=t,n.onerror=o,document.head.appendChild(n)})}o.d(t,"a",(function(){return n}))},function(e,t,o){e.exports=o(3)},function(e,t){window.NodeList&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach),[Element.prototype,CharacterData.prototype,DocumentType.prototype].forEach((function(e){e.hasOwnProperty("remove")||Object.defineProperty(e,"remove",{configurable:!0,enumerable:!0,writable:!0,value:function(){null!==this.parentNode&&this.parentNode.removeChild(this)}})}))},function(e,t,o){"use strict";o.r(t);o(2);var n=o(0);const c="6Lc76qoUAAAAALk0aYR500zOZVG1BicNl3GTb-Hu";let r;const s=(e,t)=>{const o=Math.floor(999999*Math.random())+1e5;window.grecaptcha.execute(c,{action:t+o}).then(t=>{e.value=t}),r||(r=setInterval(()=>{s(e,t)},9e4))},a=e=>{if(r)return;const t=e.dataset.action||"";Object(n.a)("https://www.google.com/recaptcha/api.js?render="+c).then(()=>{window.grecaptcha&&window.grecaptcha.ready((function(){s(e,t)}))})};(e=>{const t=document.getElementById("cookie-warning"),o=document.getElementById("cookie-agree"),n=document.getElementById("cookie-close"),c=!!r()&&localStorage.getItem("biuro-agree");function r(){try{return localStorage.setItem("a","a"),localStorage.removeItem("a"),!0}catch(e){return!1}}t&&o&&n&&!c&&(t.style.display="block",o.addEventListener("click",()=>{r()&&localStorage.setItem("biuro-agree","true"),t.style.display="none"}),n.addEventListener("click",()=>{t.style.display="none"}))})(window),(e=>{const t=document.querySelector(".c-nav--lang");t&&t.addEventListener("click",e=>{e.currentTarget.classList.toggle("c-nav--lang--is-open")})})(window),window,document.querySelectorAll(".js-toggle--nav").forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),document.body.classList.toggle("is-nav--open")})}),document.querySelectorAll(".js-toggle--aside").forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),document.body.classList.remove("is-aside--open"),document.body.classList.remove("is-aside--open-additional"),document.body.classList.remove("is-aside--open-city")})}),document.querySelectorAll(".js-toggle--aside-city").forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),document.body.classList.add("is-aside--open"),document.body.classList.remove("is-aside--open-additional"),document.body.classList.add("is-aside--open-city")})}),document.querySelectorAll(".js-toggle--aside--additional").forEach(e=>{e.addEventListener("click",e=>{e.preventDefault(),document.body.classList.toggle("is-aside--open"),document.body.classList.remove("is-aside--open-city"),document.body.classList.add("is-aside--open-additional")})}),document.querySelectorAll(".js-form--input-file").forEach(e=>{e.addEventListener("change",()=>{const t=e.parentNode,o=e.value.split(/\\|\//).pop(),n=t.querySelector(".js-form--input-file-text");n&&o&&(n.innerHTML=o)})}),document.querySelectorAll(".js-toggle--services").forEach(e=>{e.addEventListener("click",()=>{e.parentNode.classList.toggle("c-services--is-open")})}),document.querySelectorAll(".js-toggle--sections").forEach(e=>{e.addEventListener("click",()=>{const t=e.parentNode;t.classList.contains("c-sections--is-open")||document.querySelectorAll(".c-sections--is-open").forEach(e=>{e.classList.remove("c-sections--is-open")}),t.classList.toggle("c-sections--is-open")})}),document.querySelectorAll(".js-expand-jobs-section").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault(),e.parentNode.classList.remove("c-jobs-section--is-closed"),e.remove()})});const i=()=>{const e=document.querySelector('[name="s"][value="1"]');if(e)return void e.click();const t=document.querySelector('[name="name"]');t&&t.focus()};document.querySelector(".js-inititate-position-form")&&document.querySelector(".js-inititate-position-form").addEventListener("click",i),document.querySelector(".js-focus-form")&&document.querySelector(".js-focus-form").addEventListener("click",()=>{const e=document.querySelector(".c-form input:first-of-type");e&&e.focus()}),document.querySelector(".js-modal--close")&&document.querySelector(".js-modal--close").addEventListener("click",()=>{const e=document.querySelector(".c-modal");e&&e.remove();const t=document.querySelector(".c-form [autofocus]");t&&t.focus()}),(e=>{const t=document.querySelector(".c-form [autofocus]");if(t&&t.focus(),location.hash){const e=document.querySelector(".c-form--input-wrap--error input")||document.querySelector(".c-form--checkbox--error");if(e)return void e.focus();const t=document.querySelector('.c-form [name="name"]');t&&t.focus()}})(window),window,document.querySelectorAll(".gtm-share-click").forEach(e=>{e.addEventListener("click",t=>{const o=e.dataset||{};window.dataLayer=window.dataLayer||[],window.dataLayer.push({event:"shareClick",shareLabel:o.label||""})})}),document.querySelectorAll(".gtm-click").forEach(e=>{e.addEventListener("click",t=>{const o=e.dataset||{};window.dataLayer=window.dataLayer||[],window.dataLayer.push({event:o.event||"",label:o.label||""})})});document.querySelectorAll('[name="form-position"], [name="form-employees"], [name="form-employers"], [name="form-recommend"], [name="form-newsletter"]').forEach(e=>{e.addEventListener("submit",()=>{(e=>{e.querySelector('[type="submit"]')&&(e.querySelector('[type="submit"]').classList.add("c-btn--disabled"),e.querySelector('[type="submit"]').classList.add("c-btn--loading"))})(e)})}),document.querySelector("#submit-recommend")&&document.querySelector("#submit-recommend").addEventListener("click",e=>{e.preventDefault();const t=document.querySelector('[name="form-recommend"] [type="submit"]');t&&(e.currentTarget.classList.add("c-btn--disabled"),e.currentTarget.classList.add("c-btn--loading"),t.click())}),document.querySelector(".js-submit-employees-form")&&document.querySelector(".js-submit-employees-form").addEventListener("click",e=>{const t=document.querySelector('[name="form-employees"] [type="submit"]');t&&(e.preventDefault(),e.currentTarget.classList.add("c-btn--disabled"),e.currentTarget.classList.add("c-btn--loading"),t.click())}),document.querySelector(".js-accordion--header")&&async function(){const{default:e}=await o.e(0).then(o.bind(null,7));return e}().then(e=>{e()}),document.querySelector(".c-tabs")&&async function(){const{default:e}=await o.e(7).then(o.bind(null,8));return e}().then(e=>{e()});(e=>{if(!e)return;const t=()=>{(async function(){const{default:e}=await o.e(2).then(o.bind(null,9));return e})().then(e=>{e()})};if(!window.IntersectionObserver)return void t();const n=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting&&(t(),n.unobserve(e.target))})},{});n.observe(e)})(document.querySelector(".c-feedbacks--inner"));const d=()=>{const e=()=>{(async function(){const{default:e}=await o.e(1).then(o.bind(null,10));return e})().then(e=>{e()})};window.requestIdleCallback?window.requestIdleCallback(e):e()};(document.getElementById("search")||document.getElementById("form-city")||document.getElementById("recommend-form-city"))&&d(),(document.getElementById("js-map--divisions")||document.getElementById("js-map--cities")||document.getElementById("js-map--regions"))&&async function(){const{default:e}=await o.e(5).then(o.bind(null,11));return e}().then(e=>{e()}),(document.querySelector(".js-copy-to-clipboard")||document.querySelector(".js-share-messenger")||document.querySelector(".js-share-whatsapp")||document.querySelector(".js-biuro-facebook"))&&async function(){const{default:e}=await o.e(3).then(o.bind(null,12));return e}().then(e=>{e()}),async function(){const{default:e}=await o.e(6).then(o.bind(null,13));e()}(),document.querySelector(".js-collapse-row--toggle")&&document.querySelector(".js-collapse-row--toggle").addEventListener("click",e=>{e.currentTarget.parentNode.classList.toggle("c-form--row--collapsed")});const l=document.getElementById("g-recaptcha-response");l&&async function(e){if("IntersectionObserver"in window){const t=e.closest("form"),o=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting&&(a(e),o.unobserve(t.target))})},{});o.observe(t)}else window.requestIdleCallback?window.requestIdleCallback(()=>{a(e)}):a(e)}(l),(e=>{const t=document.getElementById("search");t&&document.querySelectorAll(".js-search--focus").forEach(e=>{e.addEventListener("focus",()=>{window.innerWidth<960&&t.getBoundingClientRect().top>80&&window.scroll(0,210)})})})(window),(e=>{const t="is-header--hidden",o=document.querySelector(".l-header");if(!o)return!0;let n=0,c=0,r=0,s=0,a=0;window.addEventListener("scroll",function(e,t){var o,n;return function(){const c=this,r=arguments,s=new Date;o&&s<o+e?(clearTimeout(n),n=setTimeout(()=>{o=s,t.apply(c,r)},e)):(o=s,t.apply(c,r))}}(250,(function(){n=document.body.offsetHeight,c=window.innerHeight,r=window.pageYOffset,a=s-r,r<=0||a>0&&o.classList.contains(t)?o.classList.remove(t):a<0&&(r+c>=n&&o.classList.contains(t)?o.classList.remove(t):document.body.classList.contains("is-nav--open")||o.classList.add(t)),s=r})))})(window)}]);
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -80,11 +80,9 @@ get_header(); ?> ...@@ -80,11 +80,9 @@ get_header(); ?>
</div><!-- #content --> </div><!-- #content -->
<?php <?php
$settings = pods( 'biuro_settings', array( global $biuroSettings;
'limit' => -1,
));
if ($settings->field('teams_enabled')): if ($biuroSettings->field('teams_enabled')):
get_template_part( 'template-parts/teams/teams', 'none' ); get_template_part( 'template-parts/teams/teams', 'none' );
endif; endif;
......
...@@ -20,6 +20,8 @@ get_header(); ...@@ -20,6 +20,8 @@ get_header();
<div id="content" class="l-content--position"> <div id="content" class="l-content--position">
<?php <?php
global $biuroSettings;
$ID = get_the_id(); $ID = get_the_id();
$pod = pods( 'job', $ID ); $pod = pods( 'job', $ID );
...@@ -30,17 +32,26 @@ get_header(); ...@@ -30,17 +32,26 @@ get_header();
logPositions([$livasID], 'details'); logPositions([$livasID], 'details');
endif; endif;
$settings = pods( 'biuro_settings', array(
'limit' => -1,
));
$managers = get_the_terms($pod->ID, 'member'); $managers = get_the_terms($pod->ID, 'member');
$manager = $managers[0]; $manager = $managers[0];
$isManagerVisible = $manager && $manager->term_id && $settings->field('job_page_contacts') === 'manager' ? true : false; $isManagerVisible = $manager && $manager->term_id && $biuroSettings->field('job_page_contacts') === 'manager' ? true : false;
if ($recommendPage && $biuroSettings->field('job_page_recommend_friend') == 'top'):
?>
<div class="l-content--position-banner">
<a class="c-recommend c-recommend-top" href="<?php echo $recommendPage; ?>">
<span class="c-recommend--headline"><?php _e('Recommend a friend - receive <strong>50 Eur!</strong>', 'biuro'); ?></span>
<span class="c-recommend--anchor"><?php _e('Find out more', 'biuro'); ?></span>
</a>
</div>
<?php
endif;
?> ?>
<div class="l-content--position-inner <?php echo $isManagerVisible ? 'l-content--position-inner--wide' : ''; ?>"> <div class="l-content--position-inner <?php echo $isManagerVisible ? 'l-content--position-inner--wide' : ''; ?>">
<main id="main" class="l-main l-main--position" itemscope="itemscope" itemtype="http://schema.org/JobPosting"> <main id="main" class="l-main l-main--position" itemscope="itemscope" itemtype="http://schema.org/JobPosting">
<?php <?php
......
...@@ -3,6 +3,6 @@ Theme Name: Biuro ...@@ -3,6 +3,6 @@ Theme Name: Biuro
Author: Biuro Author: Biuro
Author URI: https://www.biuro.lt/ Author URI: https://www.biuro.lt/
Description: Biuro multiregion theme Description: Biuro multiregion theme
Version: 1.21.3 Version: 1.22.0
Text Domain: biuro Text Domain: biuro
*/ */
...@@ -91,14 +91,11 @@ ...@@ -91,14 +91,11 @@
<?php <?php
global $recommendPage; global $recommendPage;
global $biuroSettings;
global $isManagerVisible; global $isManagerVisible;
global $manager; global $manager;
$settings = pods( 'biuro_settings', array( if ($recommendPage && $biuroSettings->field('job_page_recommend_friend') == 'aside'):
'limit' => -1,
));
if ($recommendPage && $settings->field('job_page_recommend_friend') == 'aside'):
?> ?>
<a class="c-recommend" href="<?php echo $recommendPage; ?>"> <a class="c-recommend" href="<?php echo $recommendPage; ?>">
<span class="c-recommend--headline"><?php _e('Recommend a friend - receive <strong>50 Eur!</strong>', 'biuro'); ?></span> <span class="c-recommend--headline"><?php _e('Recommend a friend - receive <strong>50 Eur!</strong>', 'biuro'); ?></span>
...@@ -107,7 +104,7 @@ ...@@ -107,7 +104,7 @@
<?php <?php
endif; endif;
if ($settings->field('job_page_contacts') != 'hidden'): if ($biuroSettings->field('job_page_contacts') != 'hidden'):
if ($isManagerVisible): if ($isManagerVisible):
$member = pods( 'member', $manager->term_id ); $member = pods( 'member', $manager->term_id );
...@@ -153,7 +150,7 @@ ...@@ -153,7 +150,7 @@
endif; endif;
endif; endif;
if ($settings->field('job_page_facebook') == 'visible'): if ($biuroSettings->field('job_page_facebook') == 'visible'):
$social = get_option( 'wpseo_social' ); $social = get_option( 'wpseo_social' );
...@@ -161,7 +158,7 @@ ...@@ -161,7 +158,7 @@
if ($facebook_site != ''): if ($facebook_site != ''):
?> ?>
<div class="js-biuro-facebook c-job-facebook" data-id="<?php echo $appID; ?>"> <div class="js-biuro-facebook c-job-facebook <?php echo ($isManagerVisible) ? 'c-job-facebook--wide' : ''; ?>" data-id="<?php echo $appID; ?>">
<div class="fb-page" data-href="<?php echo $facebook_site; ?>" data-tabs="" data-width="" data-height="" data-small-header="false" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote cite="<?php echo $facebook_site; ?>" class="fb-xfbml-parse-ignore"><a href="<?php echo $facebook_site; ?>">Biuro</a></blockquote></div> <div class="fb-page" data-href="<?php echo $facebook_site; ?>" data-tabs="" data-width="" data-height="" data-small-header="false" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote cite="<?php echo $facebook_site; ?>" class="fb-xfbml-parse-ignore"><a href="<?php echo $facebook_site; ?>">Biuro</a></blockquote></div>
</div> </div>
<?php <?php
......
...@@ -24,8 +24,8 @@ wp core language update; ...@@ -24,8 +24,8 @@ wp core language update;
# wp option update date_format "Y-m-d"; # wp option update date_format "Y-m-d";
# wp option update time_format "H:i"; # wp option update time_format "H:i";
# wp plugin install loco-translate --version=2.4.4 --activate-network; # wp plugin install loco-translate --version=2.4.5 --activate-network;
wp plugin update loco-translate --version=2.4.4; wp plugin update loco-translate --version=2.4.5;
# wp plugin install pods --version=2.7.24 --activate-network; # wp plugin install pods --version=2.7.24 --activate-network;
wp plugin update pods --version=2.7.24; wp plugin update pods --version=2.7.24;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment