i18nspector-0.27.1/0000755000000000000000000000000014275257157013775 5ustar00rootroot00000000000000i18nspector-0.27.1/.coveragerc0000644000000000000000000000032414275257143016110 0ustar00rootroot00000000000000[run] branch = true [report] show_missing = true exclude_lines = # no coverage \A\s+raise misc[.]DataIntegrityError\b \A\s+raise NotImplementedError\b \A\s+pass\Z # vim:ft=dosini ts=4 sts=4 sw=4 et i18nspector-0.27.1/.pylintrc0000644000000000000000000000177614275257143015650 0ustar00rootroot00000000000000[MASTER] load-plugins = pylint.extensions.check_elif [MESSAGES CONTROL] disable = bad-builtin, bad-continuation, bad-option-value, duplicate-code, fixme, inconsistent-return-statements, invalid-name, len-as-condition, locally-disabled, locally-enabled, no-else-break, no-else-continue, no-else-raise, no-else-return, no-self-use, raise-missing-from, redefined-variable-type, subprocess-popen-preexec-fn, superfluous-parens, too-few-public-methods, too-many-arguments, too-many-branches, too-many-instance-attributes, too-many-lines, too-many-locals, too-many-nested-blocks, too-many-public-methods, too-many-return-statements, too-many-statements, use-sequence-for-iteration, [BASIC] no-docstring-rgx = .* [REPORTS] reports = no score = no msg-template = {path}:{line}: {C}: {symbol} [{obj}] {msg} [FORMAT] max-line-length = 140 expected-line-ending-format = LF # vim:ft=dosini ts=4 sts=4 sw=4 et i18nspector-0.27.1/Makefile0000644000000000000000000000443614275257143015437 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON = python3 INSTALL = $(if $(shell command -v ginstall;),ginstall,install) PREFIX = /usr/local DESTDIR = bindir = $(PREFIX)/bin basedir = $(PREFIX)/share/i18nspector mandir = $(PREFIX)/share/man .PHONY: all all: ; .PHONY: install install: i18nspector # executable: $(INSTALL) -d $(DESTDIR)$(bindir) python_exe=$$($(PYTHON) -c 'import sys; print(sys.executable)') && \ sed \ -e "1 s@^#!.*@#!$$python_exe@" \ -e "s#^basedir_fallback = .*#basedir_fallback = '$(basedir)/'#" \ $(<) > $(<).tmp install $(<).tmp $(DESTDIR)$(bindir)/$(<) rm $(<).tmp # library + data: ( find lib data -type f ! -name '*.py[co]' ) \ | xargs -t -I {} $(INSTALL) -p -D -m644 {} $(DESTDIR)$(basedir)/{} ifeq "$(DESTDIR)" "" umask 022 && $(PYTHON) -m compileall -q $(basedir)/lib/ endif ifeq "$(wildcard doc/*.1)" "" # run "$(MAKE) -C doc" to build the manpage else # manual page: $(INSTALL) -p -D -m644 doc/$(<).1 $(DESTDIR)$(mandir)/man1/$(<).1 endif .PHONY: test test: $(PYTHON) -m pytest -v .PHONY: clean clean: find . -type f -name '*.py[co]' -delete find . -type d -name '__pycache__' -delete rm -rf .pytest_cache rm -f .coverage rm -f *.tmp .error = GNU make is required # vim:ts=4 sts=4 sw=4 noet i18nspector-0.27.1/data/0000755000000000000000000000000014275257143014701 5ustar00rootroot00000000000000i18nspector-0.27.1/data/charmaps/0000755000000000000000000000000014275257143016477 5ustar00rootroot00000000000000i18nspector-0.27.1/data/charmaps/GEORGIAN-PS0000644000000000000000000000066614275257143020145 0ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზჱთიკლმნჲოპჟრსტჳუფქღყშჩცძწჭხჴჯჰჵæçèéêëìíîïðñòóôõö÷øùúûüýþÿi18nspector-0.27.1/data/charmaps/KOI8-RU0000644000000000000000000000065514275257143017466 0ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓“■∙”—№™ »®«·¤═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪi18nspector-0.27.1/data/charmaps/KOI8-T0000644000000000000000000000064414275257143017341 0ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~қғ‚Ғ„…†‡￾‰ҳ‹ҲҷҶ￾Қ‘’“”•–—￾™￾›￾￾￾￾￾ӯӮё¤ӣ¦§￾￾￾«¬­®￾°±²Ё￾Ӣ¶·￾№￾»￾￾￾©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪi18nspector-0.27.1/data/charmaps/VISCII0000644000000000000000000000074014275257143017411 0ustar00rootroot00000000000000ẲẴẪ ỶỸỴ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ẠẮẰẶẤẦẨẬẼẸẾỀỂỄỆỐỒỔỖỘỢỚỜỞỊỎỌỈỦŨỤỲÕắằặấầẩậẽẹếềểễệốồổỗỠƠộờởịỰỨỪỬơớƯÀÁÂÃẢĂẳẵÈÉÊẺÌÍĨỳĐứÒÓÔạỷừửÙÚỹỵÝỡưàáâãảăữẫèéêẻìíĩỉđựòóôõỏọụùúũủýợỮi18nspector-0.27.1/data/control-characters0000644000000000000000000000113314275257143020417 0ustar00rootroot00000000000000[c0] 00 = NUL 01 = SOH 02 = STX 03 = ETX 04 = EOT 05 = ENQ 06 = ACK 07 = BEL 08 = BS 09 = HT 0a = LF 0b = VT 0c = FF 0d = CR 0e = SO 0f = SI 10 = DLE 11 = DC1 12 = DC2 13 = DC3 14 = DC4 15 = NAK 16 = SYN 17 = ETB 18 = CAN 19 = EM 1a = SUB 1b = ESC 1c = FS 1d = GS 1e = RS 1f = US [del] 7f = DEL [c1] 80 = PAD 81 = HOP 82 = BPH 83 = NBH 84 = IND 85 = NEL 86 = SSA 87 = ESA 88 = HTS 89 = HTJ 8a = VTS 8b = PLD 8c = PLU 8d = RI 8e = SS2 8f = SS3 90 = DCS 91 = PU1 92 = PU2 93 = STS 94 = CCH 95 = MW 96 = SPA 97 = EPA 98 = SOS 99 = SGC 9a = SCI 9b = CSI 9c = ST 9d = OSC 9e = PM 9f = APC # vim:ft=dosini i18nspector-0.27.1/data/encodings0000644000000000000000000000176414275257143016605 0ustar00rootroot00000000000000[portable-encodings] # PO files should use only character encodings that are supported by both GNU # libc and GNU libiconv. This section lists all of them. Unfortunately, some of # these encodings are not supported by Python. These are marked as "not-python". # https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/po-charset.c?id=v0.18.3#n57 ASCII = US-ASCII = ANSI_X3.4-1968 = ISO-8859-1 = ISO-8859-2 = ISO-8859-3 = ISO-8859-4 = ISO-8859-5 = ISO-8859-6 = ISO-8859-7 = ISO-8859-8 = ISO-8859-9 = ISO-8859-13 = ISO-8859-14 = ISO-8859-15 = KOI8-R = KOI8-U = KOI8-T = not-python CP850 = CP866 = CP874 = CP932 = CP949 = CP950 = CP1250 = CP1251 = CP1252 = CP1253 = CP1254 = CP1255 = CP1256 = CP1257 = GB2312 = EUC-JP = EUC-KR = EUC-TW = not-python BIG5 = BIG5-HKSCS = GBK = GB18030 = SHIFT_JIS = JOHAB = TIS-620 = VISCII = not-python GEORGIAN-PS = not-python UTF-8 = [extra-encodings] # encodings that are used by real-world PO/MO files, # but are not known to Python KOI8-RU = # vim:ft=dosini i18nspector-0.27.1/data/header-fields0000644000000000000000000000065514275257143017326 0ustar00rootroot00000000000000# This file has been generated automatically by # private/update-header-fields. Do not edit. # # The following string extraction tools have been used: # * pygettext.py (xgettext for Python) 1.5 # * xgettext (GNU gettext-tools) 0.19.5.1 Content-Transfer-Encoding Content-Type Generated-By Language Language-Team Last-Translator MIME-Version PO-Revision-Date POT-Creation-Date Plural-Forms Project-Id-Version Report-Msgid-Bugs-To i18nspector-0.27.1/data/iso-codes0000644000000000000000000001105514275257143016513 0ustar00rootroot00000000000000# This file has been generated automatically by private/update-iso-codes. # Do not edit. # iso-codes version: 3.66 # Last update: 2016-03-19 [language-codes] aar = aa abk = ab ace = ach = ada = ady = afh = afr = af ain = aka = ak akk = alb = sq ale = alt = amh = am ang = anp = ara = ar arc = arg = an arm = hy arn = arp = arw = asm = as ast = ava = av ave = ae awa = aym = ay aze = az bak = ba bal = bam = bm ban = baq = eu bas = bej = bel = be bem = ben = bn bho = bik = bin = bis = bi bla = bod = bo bos = bs bra = bre = br bua = bug = bul = bg bur = my byn = cad = car = cat = ca ceb = ces = cs cha = ch chb = che = ce chg = chi = zh chk = chm = chn = cho = chp = chr = chu = cu chv = cv chy = cop = cor = kw cos = co cre = cr crh = csb = cym = cy cze = cs dak = dan = da dar = del = den = deu = de dgr = din = div = dv doi = dsb = dua = dum = dut = nl dyu = dzo = dz efi = egy = eka = ell = el elx = eng = en enm = epo = eo est = et eus = eu ewe = ee ewo = fan = fao = fo fas = fa fat = fij = fj fil = fin = fi fon = fra = fr fre = fr frm = fro = frr = frs = fry = fy ful = ff fur = gaa = gay = gba = geo = ka ger = de gez = gil = gla = gd gle = ga glg = gl glv = gv gmh = goh = gon = gor = got = grb = grc = gre = el grn = gn gsw = guj = gu gwi = hai = hat = ht hau = ha haw = heb = he her = hz hil = hin = hi hit = hmn = hmo = ho hrv = hr hsb = hun = hu hup = hye = hy iba = ibo = ig ice = is ido = io iii = ii iku = iu ile = ie ilo = ina = ia ind = id inh = ipk = ik isl = is ita = it jav = jv jbo = jpn = ja jpr = jrb = kaa = kab = kac = kal = kl kam = kan = kn kas = ks kat = ka kau = kr kaw = kaz = kk kbd = kha = khm = km kho = kik = ki kin = rw kir = ky kmb = kok = kom = kv kon = kg kor = ko kos = kpe = krc = krl = kru = kua = kj kum = kur = ku kut = lad = lah = lam = lao = lo lat = la lav = lv lez = lim = li lin = ln lit = lt lol = loz = ltz = lb lua = lub = lu lug = lg lui = lun = luo = lus = mac = mk mad = mag = mah = mh mai = mak = mal = ml man = mao = mi mar = mr mas = may = ms mdf = mdr = men = mga = mic = min = mkd = mk mlg = mg mlt = mt mnc = mni = moh = mon = mn mos = mri = mi msa = ms mus = mwl = mwr = mya = my myv = nap = nau = na nav = nv nbl = nr nde = nd ndo = ng nds = nep = ne new = nia = niu = nld = nl nno = nn nob = nb nog = non = nor = no nqo = nso = nwc = nya = ny nym = nyn = nyo = nzi = oci = oc oji = oj ori = or orm = om osa = oss = os ota = pag = pal = pam = pan = pa pap = pau = peo = per = fa phn = pli = pi pol = pl pon = por = pt pro = pus = ps que = qu raj = rap = rar = roh = rm rom = ron = ro rum = ro run = rn rup = rus = ru sad = sag = sg sah = sam = san = sa sas = sat = scn = sco = sel = sga = shn = sid = sin = si slk = sk slo = sk slv = sl sma = sme = se smj = smn = smo = sm sms = sna = sn snd = sd snk = sog = som = so sot = st spa = es sqi = sq srd = sc srn = srp = sr srr = ssw = ss suk = sun = su sus = sux = swa = sw swe = sv syc = syr = tah = ty tam = ta tat = tt tel = te tem = ter = tet = tgk = tg tgl = tl tha = th tib = bo tig = tir = ti tiv = tkl = tlh = tli = tmh = tog = ton = to tpi = tsi = tsn = tn tso = ts tuk = tk tum = tur = tr tvl = twi = tw tyv = udm = uga = uig = ug ukr = uk umb = urd = ur uzb = uz vai = ven = ve vie = vi vol = vo vot = wal = war = was = wel = cy wln = wa wol = wo xal = xho = xh yao = yap = yid = yi yor = yo zap = zbl = zen = zha = za zho = zh zul = zu zun = zza = [territory-codes] AD = AE = AF = AG = AI = AL = AM = AO = AQ = AR = AS = AT = AU = AW = AX = AZ = BA = BB = BD = BE = BF = BG = BH = BI = BJ = BL = BM = BN = BO = BQ = BR = BS = BT = BV = BW = BY = BZ = CA = CC = CD = CF = CG = CH = CI = CK = CL = CM = CN = CO = CR = CU = CV = CW = CX = CY = CZ = DE = DJ = DK = DM = DO = DZ = EC = EE = EG = EH = ER = ES = ET = FI = FJ = FK = FM = FO = FR = GA = GB = GD = GE = GF = GG = GH = GI = GL = GM = GN = GP = GQ = GR = GS = GT = GU = GW = GY = HK = HM = HN = HR = HT = HU = ID = IE = IL = IM = IN = IO = IQ = IR = IS = IT = JE = JM = JO = JP = KE = KG = KH = KI = KM = KN = KP = KR = KW = KY = KZ = LA = LB = LC = LI = LK = LR = LS = LT = LU = LV = LY = MA = MC = MD = ME = MF = MG = MH = MK = ML = MM = MN = MO = MP = MQ = MR = MS = MT = MU = MV = MW = MX = MY = MZ = NA = NC = NE = NF = NG = NI = NL = NO = NP = NR = NU = NZ = OM = PA = PE = PF = PG = PH = PK = PL = PM = PN = PR = PS = PT = PW = PY = QA = RE = RO = RS = RU = RW = SA = SB = SC = SD = SE = SG = SH = SI = SJ = SK = SL = SM = SN = SO = SR = SS = ST = SV = SX = SY = SZ = TC = TD = TF = TG = TH = TJ = TK = TL = TM = TN = TO = TR = TT = TV = TW = TZ = UA = UG = UM = US = UY = UZ = VA = VC = VE = VG = VI = VN = VU = WF = WS = YE = YT = ZA = ZM = ZW = # vim:ft=dosini i18nspector-0.27.1/data/languages0000644000000000000000000010155714275257143016603 0ustar00rootroot00000000000000# This file should describe only the languages that fall into one of the # following categories: # - languages that have an ISO 639-1 two-letter code; # - languages recognized by poedit; # - languages for which real-world PO files exist. # ISO 639-2 codes for collections of languages # should normally not be added here. # See: https://iso639-3.sil.org/about/scope#Collections%20of%20languages [aa] names = Afar [ab] names = Abkhazian characters = а б в г ӷ д е ж з ӡ и к қ ҟ л м н о п ԥ р с т ҭ у ф х ҳ ц ҵ ч ҷ ҽ ҿ ш ы ҩ џ ь ә А Б В Г Ӷ Д Е Ж З Ӡ И К Қ Ҟ Л М Н О П Ԥ Р С Т Ҭ У Ф Х Ҳ Ц Ҵ Ч Ҷ Ҽ Ҿ Ш Ы Ҩ Џ Ь Ә [ace] names = Achinese principal-territory = ID [ach] names = Acoli [ady] names = Adyghe Adygei characters = а б в г д е (ё) ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э (ю) я А Б В Г Д Е (Ё) Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э (Ю) Я Ӏ [ae] names = Avestan [af] names = Afrikaans principal-territory = ZA plural-forms = nplurals=2; plural=n != 1; [ak] names = Akan principal-territory = GH [am] names = Amharic characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሏ ሐ ሑ ሒ ሓ ሔ ሕ ሖ ሗ መ ሙ ሚ ማ ሜ ም ሞ ሟ ሠ ሡ ሢ ሣ ሤ ሥ ሦ ሧ ረ ሩ ሪ ራ ሬ ር ሮ ሯ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሷ ሸ ሹ ሺ ሻ ሼ ሽ ሾ ሿ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቈ ቊ ቋ ቌ ቍ በ ቡ ቢ ባ ቤ ብ ቦ ቧ ቨ ቩ ቪ ቫ ቬ ቭ ቮ ቯ ተ ቱ ቲ ታ ቴ ት ቶ ቷ ቸ ቹ ቺ ቻ ቼ ች ቾ ቿ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኈ ኊ ኋ ኌ ኍ ነ ኑ ኒ ና ኔ ን ኖ ኗ ኘ ኙ ኚ ኛ ኜ ኝ ኞ ኟ አ ኡ ኢ ኣ ኤ እ ኦ ኧ ከ ኩ ኪ ካ ኬ ክ ኮ ኰ ኲ ኳ ኴ ኵ ኸ ኹ ኺ ኻ ኼ ኽ ኾ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዟ ዠ ዡ ዢ ዣ ዤ ዥ ዦ ዧ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ዷ ጀ ጁ ጂ ጃ ጄ ጅ ጆ ጇ ገ ጉ ጊ ጋ ጌ ግ ጎ ጐ ጒ ጓ ጔ ጕ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጧ ጨ ጩ ጪ ጫ ጬ ጭ ጮ ጯ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጷ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ጿ ፀ ፁ ፂ ፃ ፄ ፅ ፆ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፏ ፐ ፑ ፒ ፓ ፔ ፕ ፖ ፗ plural-forms = nplurals=2; plural=n > 1; principal-territory = ET [an] names = Aragonese principal-territory = ES [ang] names = Old English principal-territory = GB [ar] names = Arabic characters = ا ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي [as] names = Assamese characters = অ আ ই ঈ উ ঊ ঋ ৠ ঌ ৡ এ ঐ ও ঔ ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত ৎ থ দ ধ ন প ফ ব ভ ম য ৰ ল ৱ শ ষ স হ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [ast] names = Asturian Bable Leonese Asturleonese characters = á é í ñ ó ú (ü) Á É Í Ñ Ó Ú (Ü) plural-forms = nplurals=2; plural=n != 1; principal-territory = ES [av] names = Avaric principal-territory = RU [ay] names = Aymara [az] names = Azerbaijani ç ə ğ ı i ö ş ü Ç Ə Ğ I İ Ö Ş Ü principal-territory = AZ [ba] names = Bashkir [bal] names = Baluchi [be] names = Belarusian characters = а б в г д е ё ж з і й к л м н о п р с т у ў ф х ц ч ш ы ь э ю я А Б В Г Д Е Ё Ж З І Й К Л М Н О П Р С Т У Ў Ф Х Ц Ч Ш Ы Ь Э Ю Я characters@latin = ć č ł ń ś š ŭ ź ž Ć Č Ł Ń Ś Š Ŭ Ź Ž plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = BY [bem] names = Bemba principal-territory = ZM [bg] names = Bulgarian characters = а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ь ю я А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ь Ю Я plural-forms = nplurals=2; plural=n != 1; principal-territory = BG [bho] names = Bhojpuri principal-territory = IN [bi] names = Bislama [bm] names = Bambara principal-territory = ML [bn] names = Bengali characters = অ আ ই ঈ উ ঊ ঋ এ ঐ ও ঔ ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত থ দ ধ ন প ফ ব ভ ম য র ল শ ষ স হ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [bo] names = Tibetan principal-territory = CN [br] names = Breton characters = â ê î ô û ù ü ñ Â Ê Î Ô Û Ù Ü Ñ plural-forms = nplurals=2; plural=n > 1; principal-territory = FR [bs] names = Bosnian characters = đ ž ć č š Đ Ž Ć Č Š plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = BA [byn] names = Blin Bilin [ca] names = Catalan Valencian characters = à é è í ï ó ò ú ü ç À É È Í Ï Ó Ò Ú Ü Ç plural-forms = nplurals=2; plural=n != 1; principal-territory = ES [ce] names = Chechen principal-territory = RU [ceb] names = Cebuano principal-territory = PH [ch] names = Chamorro [co] names = Corsican characters = à è ì ï ò ù ü À È Ì Ï Ò Ù Ü principal-territory = FR [cr] names = Cree principal-territory = CA [crh] names = Crimean Tatar Crimean Turkish characters = â ç ğ ı i ñ ö ş ü Â Ç Ğ I İ Ñ Ö Ş Ü [cs] names = Czech characters = á č ď é ě í ň ó ř š ť ú ů ý ž Á Č Ď É Ě Í Ň Ó Ř Š Ť Ú Ů Ý Ž plural-forms = nplurals=3; plural=n==1 ? 0 : (n>=2 && n<=4) ? 1 : 2; principal-territory = CZ [csb] names = Kashubian characters = ą ã é ë ł ń ò ó ô ù ż Ą Ã É Ë Ł Ń Ò Ó Ô Ù Ż principal-territory = PL [cu] names = Church Slavic Church Slavonic Old Bulgarian Old Church Slavonic Old Slavonic [cv] names = Chuvash [cy] names = Welsh characters = â ê î ô û ŵ ŷ Â Ê Î Ô Û Ŵ Ŷ principal-territory = GB [da] names = Danish characters = æ ø å Æ Ø Å plural-forms = nplurals=2; plural=n != 1; principal-territory = DK [de] names = German characters = ä ö ü ß Ä Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = DE [doi] names = Dogri principal-territory = IN [dv] names = Dhivehi Divehi Maldivian principal-territory = MV [dz] names = Dzongkha # for simplicity, only consonants are included here; # they should be sufficient for i18nspector purposes: characters = ཀ ཁ ག ང ཅ ཆ ཇ ཉ ཏ ཐ ད ན པ ཕ བ མ ཙ ཚ ཛ ཝ ཞ ཟ འ ཡ ར ལ ཤ ས ཧ ཨ principal-territory = BT [ee] names = Ewe principal-territory = GH [el] names = Greek characters = α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ ς τ υ φ χ ψ ω Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω plural-forms = nplurals=2; plural=n != 1; principal-territory = GR [en] names = English characters@quot = ‘ ’ characters@boldquot = ‘ ’ characters@shaw = 𐑐 𐑑 𐑒 𐑓 𐑔 𐑕 𐑖 𐑗 𐑘 𐑙 𐑚 𐑛 𐑜 𐑝 𐑞 𐑟 𐑠 𐑡 𐑢 𐑣 𐑤 𐑥 𐑦 𐑧 𐑨 𐑩 𐑪 𐑫 𐑬 𐑭 𐑮 𐑯 𐑰 𐑱 𐑲 𐑳 𐑴 𐑵 𐑶 𐑷 𐑸 𐑹 𐑺 𐑻 𐑼 𐑽 𐑾 𐑿 plural-forms = nplurals=2; plural=n != 1; [en_AU] names = Australian English [en_CA] names = Canadian English [en_GB] names = British English [en_US] names = American English [eo] names = Esperanto characters = ĉ ĝ ĥ ĵ ŝ ŭ Ĉ Ĝ Ĥ Ĵ Ŝ Ŭ plural-forms = nplurals=2; plural=n != 1; [es] names = Spanish characters = á é í ñ ó ú (ü) Á É Í Ñ Ó Ú (Ü) plural-forms = nplurals=2; plural=n != 1; principal-territory = ES [et] names = Estonian characters = (š) (ž) õ ä ö ü (Š) (Ž) Õ Ä Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = EE [eu] names = Basque characters = (ç) ñ (Ç) Ñ plural-forms = nplurals=2; plural=n != 1; [fa] names = Persian characters = ا ب پ ت ث ج چ ح خ د ذ ر ز ژ س ش ص ض ط ظ ع غ ف ق ک گ ل م ن و ه ی plural-forms = nplurals=1; plural=0; principal-territory = IR [ff] names = Fulah [fi] names = Finnish characters = (š) (ž) å ä ö (Š) (Ž) Å Ä Ö plural-forms = nplurals=2; plural=n != 1; principal-territory = FI [fil] names = Filipino Pilipino principal-territory = PH [fj] names = Fijian principal-territory = FJ [fo] names = Faroese characters = á ð í ó ú ý æ ø Á Ð Í Ó Ú Ý Æ Ø plural-forms = nplurals=2; plural=n != 1; principal-territory = FO [fr] names = French characters = à â (æ) ç é è ê ë î ï ô (œ) ù û ü ÿ À  (Æ) Ç É È Ê Ë Î Ï Ô (Œ) Ù Û Ü (Ÿ) plural-forms = nplurals=2; plural=n > 1; principal-territory = FR [fur] names = Friulian principal-territory = IT [fy] names = Frisian Western Frisian characters = â ê é ô û ú Â Ê É Ô Û Ú plural-forms = nplurals=2; plural=n != 1; principal-territory = NL [ga] names = Irish characters = á é í ó ú Á É Í Ó Ú # plural-forms = nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2; principal-territory = IE [gaa] names = Ga [gd] names = Gaelic Scottish Gaelic characters = à è ì ò ù À È Ì Ò Ù principal-territory = GB [gez] names = Geez characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሏ ሐ ሑ ሒ ሓ ሔ ሕ ሖ ሗ መ ሙ ሚ ማ ሜ ም ሞ ሟ ፙ ሠ ሡ ሢ ሣ ሤ ሥ ሦ ሧ ረ ሩ ሪ ራ ሬ ር ሮ ሯ ፘ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሷ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቋ በ ቡ ቢ ባ ቤ ብ ቦ ቧ ተ ቱ ቲ ታ ቴ ት ቶ ቷ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኋ ነ ኑ ኒ ና ኔ ን ኖ ኗ አ ኡ ኢ ኣ ኤ እ ኦ ኧ ከ ኩ ኪ ካ ኬ ክ ኮ ኳ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዟ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ዷ ገ ጉ ጊ ጋ ጌ ግ ጎ ጓ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጧ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጷ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ጿ ፀ ፁ ፂ ፃ ፄ ፅ ፆ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፏ ፚ ፐ ፑ ፒ ፓ ፔ ፕ ፖ ፗ [gl] names = Galician characters = á é í ñ ó ú Á É Í Ñ Ó Ú plural-forms = nplurals=2; plural=n != 1; [gn] names = Guarani [gu] names = Gujarati characters = અ આ ઇ ઈ ઉ ઊ ઋ એ ઐ ઓ ઔ ક ખ ગ ઘ ઙ ચ છ જ ઝ ઞ ટ ઠ ડ ઢ ણ ત થ દ ધ ન પ ફ બ ભ મ ય ર લ વ શ ષ સ હ ળ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [gv] names = Manx [ha] names = Hausa [haw] names = Hawaiian [he] names = Hebrew characters = א ב ג ד ה ו ז ח ט י כ ל מ נ ס ע פ צ ק ר ש ת plural-forms = nplurals=2; plural=n != 1; principal-territory = IL [hi] names = Hindi characters = अ आ इ ई उ ऊ ए ऐ ओ औ क ख ख़ ग ग॒ ग़ घ ङ च छ ज ज॒ ज़ झ ञ ट ठ ड ड॒ ड़ ढ ढ़ ण त थ द ध न प फ फ़ ब ब॒ भ म य र ल व श ष स ह plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [ho] names = Hiri Motu [hr] names = Croatian characters = đ ž ć č š Đ Ž Ć Č Š plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = HR [ht] names = Haitian Haitian Creole principal-territory = HT [hu] names = Hungarian characters = á é í ó ö ő ú ü ű Á É Í Ó Ö Ő Ú Ü Ű plural-forms = nplurals=1; plural=0; nplurals=2; plural=n != 1; principal-territory = HU [hy] names = Armenian characters = ա բ գ դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն շ ո չ պ ջ ռ ս վ տ ր ց ւ փ ք և օ ֆ Ա Բ Գ Դ Ե Զ Է Ը Թ Ժ Ի Լ Խ Ծ Կ Հ Ձ Ղ Ճ Մ Յ Ն Շ Ո Չ Պ Ջ Ռ Ս Վ Տ Ր Ց Ւ Փ Ք Օ Ֆ principal-territory = AM [hz] names = Herero [ia] names = Interlingua plural-forms = nplurals=2; plural=n != 1; [id] names = Indonesian plural-forms = nplurals=1; plural=0; principal-territory = ID [ie] names = Interlingue Occidental [ig] names = Igbo principal-territory = NG [ii] names = Nuosu Sichuan Yi principal-territory = CN [ik] names = Inupiaq [ilo] names = Iloko principal-territory = PH [io] names = Ido [is] names = Icelandic characters = á ð é í ó ú ý þ æ ö Á Ð É Í Ó Ú Ý Þ Æ Ö principal-territory = IS [it] names = Italian characters = à è é ì í î ò ó ù ú À È É Ì Í Î Ò Ó Ù Ú plural-forms = nplurals=2; plural=n != 1; principal-territory = IT [iu] names = Inuktitut [ja] names = Japanese characters = # Hiragana: あ い う え お か き く け こ さ し す せ そ た ち つ て と な に ぬ ね の は ひ ふ へ ほ ま み む め も や ゆ よ ら り る れ ろ わ ゐ ゑ を ん # Katakana: ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ ル レ ロ ワ ヰ ヱ ヲ ン # Kanji (the list of ideograms is incomplete; # only the 100 most often used ones are included here): 以 一 下 化 加 可 解 開 外 確 間 起 検 見 現 後 効 更 行 合 込 再 最 在 作 削 使 始 指 字 時 次 示 自 失 実 者 取 終 集 出 書 除 小 上 場 情 新 数 成 正 生 切 設 先 選 前 全 続 存 他 大 択 値 置 中 追 通 定 的 度 動 読 内 日 入 認 能 敗 発 必 表 不 付 分 文 変 保 報 方 無 名 明 有 用 要 利 理 了 力 plural-forms = nplurals=1; plural=0; principal-territory = JP [jbo] names = Lojban [jv] names = Javanese principal-territory = ID [ka] names = Georgian characters = ა ბ გ დ ე ვ ზ (ჱ) თ ი კ ლ მ ნ (ჲ) ო პ ჟ რ ს ტ (ჳ) უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ (ჴ) ჯ ჰ (ჵ) (ჶ) (ჷ) (ჺ) (ჸ) (ჹ) plural-forms = nplurals=1; plural=0; principal-territory = GE [kab] names = Kabyle principal-territory = DZ [kg] names = Kongo principal-territory = CD [ki] names = Gikuyu Kikuyu [kj] names = Kuanyama Kwanyama [kk] names = Kazakh characters = а ә б в г ғ д е ё ж з и й к қ л м н ң о ө п р с т у ұ ү ф х һ ц ч ш щ ъ ы і ь э ю я А Ә Б В Г Ғ Д Е Ё Ж З И Й К Қ Л М Н Ң О Ө П Р С Т У Ұ Ү Ф Х Һ Ц Ч Ш Щ Ъ Ы І Ь Э Ю Я plural-forms = nplurals=1; plural=0; principal-territory = KZ [kl] names = Greenlandic Kalaallisut principal-territory = GL [km] names = Central Khmer Khmer # for simplicity, only consonants are included here; # they should be sufficient for i18nspector purposes: characters = ក ខ គ ឃ ង ច ឆ ជ ឈ ញ ដ ឋ ឌ ឍ ណ ត ថ ទ ធ ន ប ផ ព ភ ម យ រ ល វ ឝ ឞ ស ហ ឡ អ plural-forms = nplurals=1; plural=0; principal-territory = KH [kn] names = Kannada characters = ಅ ಆ ಇ ಈ ಉ ಊ ಋ ೠ ಌ ೡ ಎ ಏ ಐ ಒ ಓ ಔ ಕ ಖ ಗ ಘ ಙ ಚ ಛ ಜ ಝ ಞ ಟ ಠ ಡ ಢ ಣ ತ ಥ ದ ಧ ನ ಪ ಫ ಬ ಭ ಮ ಯ ರ ಱ ಲ ವ ಶ ಷ ಸ ಹ ಳ ೞ principal-territory = IN [ko] names = Korean characters = # The list of Hangul syllables is incomplete; # only the 100 most often used ones are included here. 가 경 고 과 구 그 기 나 는 니 다 대 데 도 동 되 된 드 디 라 러 력 로 록 류 를 름 리 마 만 면 명 모 목 미 바 보 부 비 사 상 서 선 설 성 소 수 스 습 시 실 십 아 않 어 없 에 여 오 용 우 원 위 으 은 을 음 의 이 인 일 입 있 자 작 장 재 저 전 정 제 주 중 지 추 치 크 택 터 트 파 표 프 하 한 할 합 해 행 화 plural-forms = nplurals=1; plural=0; principal-territory = KR [kok] names = Konkani principal-territory = IN [kos] names = Kosraean [kr] names = Kanuri principal-territory = NG [ks] names = Kashmiri [ku] names = Kurdish characters = ç ê î ş û Ç Ê Î Ş Û plural-forms = nplurals=2; plural=n != 1; [kv] names = Komi [kw] names = Cornish [ky] names = Kirghiz Kyrgyz characters = а б в г д е ё ж з и й к л м н ң о ө п р с т у ү ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н Ң О Ө П Р С Т У Ү Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я [la] names = Latin [lb] names = Letzeburgesch Luxembourgish [lg] names = Ganda principal-territory = UG [li] names = Limburgan principal-territory = BE [ln] names = Lingala [lo] names = Lao principal-territory = LA [lt] names = Lithuanian characters = ą č ę ė į š ų ū ž Ą Č Ę Ė Į Š Ų Ū Ž plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = LT [lu] names = Luba-Katanga principal-territory = CD [lv] names = Latvian characters = ā č ē ģ ī ķ ļ ņ š ū ž Ā Č Ē Ģ Ī Ķ Ļ Ņ Š Ū Ž plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; principal-territory = LV [mai] names = Maithili plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [mg] names = Malagasy characters = à â é è ê ë ì î ï ñ ô À Â É È Ê Ë Ì Î Ï Ñ Ô plural-forms = nplurals=2; plural=n > 1; principal-territory = MG [mh] names = Marshall Marshallese [mi] names = Maori characters = ā ē ī ō ū Ā Ē Ī Ō Ū principal-territory = NZ [mk] names = Macedonian characters = а б в г д ѓ е ж з ѕ и ј к л љ м н њ о п р с т ќ у ф х ц ч џ ш А Б В Г Д Ѓ Е Ж З Ѕ И Ј К Л Љ М Н Њ О П Р С Т Ќ У Ф Х Ц Ч Џ Ш principal-territory = MK [ml] names = Malayalam characters = അ ആ ഇ ഈ ഉ ഊ ഋ എ ഏ ഐ ഒ ഓ ഔ ക ഖ ഗ ഘ ങ ച ഛ ജ ഝ ഞ ട ഠ ഡ ഢ ണ ത ഥ ദ ധ ന പ ഫ ബ ഭ മ യ ര ല വ ശ ഷ സ ഹ ള ഴ റ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [mn] names = Mongolian characters = а б в г д е ё ж з и й к л м н о ө п р с т у ү ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н О Ө П Р С Т У Ү Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я plural-forms = nplurals=2; plural=n != 1; principal-territory = MN [mni] names = Manipuri principal-territory = IN [mr] names = Marathi characters = अ आ इ ई उ ऊ ऋ ऌ ए ऐ ऑ ओ औ क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न प फ ब भ म य र ल व श ष स ह ळ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [ms] names = Malay principal-territory = MY [mt] names = Maltese characters = Ċ Ġ ħ Ħ Ż ċ ġ ħ ħ ż principal-territory = MT [mus] names = Creek [my] names = Burmese characters = က ခ ဂ ဃ င စ ဆ ဇ ဈ ဉ ည ဋ ဌ ဍ ဎ ဏ တ ထ ဒ ဓ န ပ ဖ ဗ ဘ မ ယ ရ လ ဝ သ ဟ ဠ principal-territory = MM [na] names = Nauru principal-territory = NR [nap] names = Neapolitan principal-territory = IT [nb] names = Norwegian Bokmål characters = æ ø å Æ Ø Å plural-forms = nplurals=2; plural=n != 1; principal-territory = NO [nd] names = North Ndebele [nds] names = Low German Low Saxon characters = ä ö ü ß Ä Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = DE [ne] names = Nepali characters = अ आ इ ई उ ऊ ऋ ए ऐ ओ औ क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न प फ ब भ म य र ल व श ष स ह plural-forms = nplurals=2; plural=n != 1; principal-territory = NP [ng] names = Ndonga [nl] names = Dutch Flemish characters = ä ë ï (ij) ö ü Ä Ë Ï (IJ) Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = NL [nn] names = Norwegian Nynorsk characters = æ ø å Æ Ø Å plural-forms = nplurals=2; plural=n != 1; principal-territory = NO [no] names = Norwegian characters = æ ø å Æ Ø Å macrolanguage = nb nn plural-forms = nplurals=2; plural=n != 1; principal-territory = NO [nr] names = South Ndebele principal-territory = ZA [nso] names = Pedi Sepedi Northern Sotho principal-territory = ZA [nv] names = Navaho Navajo [ny] names = Chichewa Chewa Nyanja [oc] names = Occitan characters = à á ç è é í ï ò ó ú ü À Á Ç È É Í Ï Ò Ó Ú Ü plural-forms = nplurals=2; plural=n > 1; principal-territory = FR [oj] names = Ojibwa principal-territory = CA [om] names = Oromo [or] names = Oriya characters = ଅ ଆ ଇ ଈ ଉ ଊ ଋ ଏ ଐ ଓ ଔ କ ଖ ଗ ଘ ଙ ଚ ଛ ଜ ଝ ଞ ଟ ଠ ଡ ଢ ଣ ତ ଥ ଦ ଧ ନ ପ ଫ ବ ଭ ମ ଯ ର ଲ ଳ ଶ ଷ ସ ହ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [os] names = Ossetian Ossetic characters = a ӕ б в г д дж дз е з и й к л м н о п р с т у ф х ц ч ы ъ А Ӕ Б В Г Д ДЖ ДЗ Е З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ы Ъ [pa] names = Panjabi Punjabi characters = ੴ ੳ ਉ ਊ ਓ ਅ ਆ ਐ ਔ ੲ ਇ ਈ ਏ ਸ ਹ ਕ ਖ ਗ ਘ ਙ ਚ ਛ ਜ ਝ ਞ ਟ ਠ ਡ ਢ ਣ ਤ ਥ ਦ ਧ ਨ ਪ ਫ ਬ ਭ ਮ ਯ ਰ ਲ ਵ ੜ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [pap] names = Papiamento [pi] names = Pali [pl] names = Polish characters = ą ć ę ó ł ń ó ś ż ź Ą Ć Ę Ó Ł Ń Ó Ś Ż Ź plural-forms = nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = PL [ps] names = Pashto Pushto characters = آ آ ب پ ت ټ ث ج چ ح خ څ ځ د ډ ﺫ ﺭ ړ ﺯ ژ ږ س ش ښ ص ض ط ظ ع غ ف ق ک ګ ل م ن ڼ و ه ي ې ی ۍ ئ plural-forms = nplurals=2; plural=n != 1; principal-territory = AF [pt] names = Portuguese characters = á â ã à ç é ê í ó ô õ ú Á  à À Ç É Ê Í Ó Ô Õ Ú plural-forms = nplurals=2; plural=n != 1; principal-territory = PT [pt_BR] names = Brazilian Brazilian Portuguese plural-forms = nplurals=2; plural=n > 1; [qu] names = Quechua [rm] names = Rhaeto-Romance Romansh principal-territory = CH [rn] names = Rundi principal-territory = BI [ro] names = Romanian characters = ă â î ș ț Ă Â Î Ș Ț plural-forms = nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; principal-territory = RO [ro_MD] names = Moldavian Moldovan plural-forms = nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; [ru] names = Russian characters = а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = RU [rw] names = Kinyarwanda plural-forms = nplurals=2; plural=n != 1; [sa] names = Sanskrit principal-territory = IN [sat] names = Santali principal-territory = IN [sc] names = Sardinian principal-territory = IT [sco] names = Scots [sd] names = Sindhi characters = جھ ڄ ج پ ث ٺ ٽ ٿ ت ڀ ٻ ب ا ڙ ر ذ ڍ ڊ ڏ ڌ د خ ح ڇ چ ڃ ق ڦ ف غ ع ظ ط ض ص ش س ز ڙھ ي ه و ڻ ن م ل ڱ گھ ڳ گ ک ڪ characters@devanagari = अ आ इ ई उ ऊ ए ऐ ओ औ क ख ख़ ग ग॒ ग़ घ ङ च छ ज ज॒ ज़ झ ञ ट ठ ड ड॒ ड़ ढ ढ़ ण त थ द ध न प फ फ़ ब ब॒ भ म य र ल व श ष स ह [se] names = Northern Sami characters = á č đ ŋ š ŧ ž Á Č Đ Ŋ Š Ŧ Ž [sg] names = Sango Sangro principal-territory = CF [shn] names = Shan principal-territory = MM [si] names = Sinhala Sinhalese # for simplicity, only consonants are included here; # they should be sufficient for i18nspector purposes: characters = ක ග (ච) ජ ට ඩ ණ ත ද න ප බ ම ය ර ල ව ස හ ළ plural-forms = nplurals=2; plural=n != 1; principal-territory = LK [sk] names = Slovak characters = á ä č ď ž é í ĺ ľ ň ó ô ŕ š ť ú ý ž Á Ä Č Ď Ž É Í Ĺ Ľ Ň Ó Ô Ŕ Š Ť Ú Ý Ž # plural-forms = nplurals=3; plural=n==1 ? 0 : (n>=2 && n<=4) ? 1 : 2; principal-territory = SK [sl] names = Slovenian characters = č š ž Č Š Ž # plural-forms = nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; # https://savannah.gnu.org/bugs/?45591 principal-territory = SI [sm] names = Samoan [sn] names = Shona [so] names = Somali principal-territory = SO [sq] names = Albanian characters = ç ë Ç Ë plural-forms = nplurals=2; plural=n != 1; principal-territory = AL [sr] names = Serbian characters = а б в г д ђ е ж з и ј к л љ м н њ о п р с т ћ у ф х ц ч џ ш А Б В Г Д Ђ Е Ж З И Ј К Л Љ М Н Њ О П Р С Т Ћ У Ф Х Ц Ч Џ Ш characters@latin = đ ž ć č š Đ Ž Ć Č Š characters@ijekavianlatin = đ ž ć č š Đ Ž Ć Č Š plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = RS [ss] names = Swati Siswati [st] names = Sesotho Southern Sotho [su] names = Sundanese [sv] names = Swedish characters = å ä ö Å Ä Ö plural-forms = nplurals=2; plural=n != 1; principal-territory = SE [sw] names = Swahili [ta] names = Tamil characters = அ ஆ இ ஈ உ ஊ எ ஏ ஐ ஒ ஓ ஔ க ங ச ஞ ட ண த ந ப ம ய ர ல வ ழ ள ற ன ஜ ஶ ஷ ஸ ஹ plural-forms = nplurals=2; plural=n != 1; [te] names = Telugu characters = అ ఆ ఇ ఈ ఉ ఊ ఋ ౠ ఎ ఏ ఐ ఒ ఓ ఔ క ఖ గ ఘ ఙ చ ఛ జ ఝ ఞ ట ఠ డ ఢ ణ త థ ద ధ న ప ఫ బ భ మ య ర ఱ ల వ శ ష స హ ళ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [tet] names = Tetum principal-territory = ID [tg] names = Tajik characters = а б в г ғ д е ё ж з и ӣ й к қ л м н о п р с т у ӯ ф х ҳ ч ҷ ш ъ э ю я А Б В Г Ғ Д Е Ё Ж З И Ӣ Й К Қ Л М Н О П Р С Т У Ӯ Ф Х Ҳ Ч Ҷ Ш Ъ Э Ю Я plural-forms = nplurals=2; plural=n != 1; principal-territory = TJ [th] names = Thai characters = ก ข ฃ ค ฅ ฆ ง จ ฉ ช ซ ฌ ญ ฎ ฏ ฐ ฑ ฒ ณ ด ต ถ ท ธ น บ ป ผ ฝ พ ฟ ภ ม ย ร ล ว ศ ษ ส ห ฬ อ ฮ plural-forms = nplurals=1; plural=0; principal-territory = TH [ti] names = Tigrinya characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሐ ሑ ሒ ሓ ሔ ሕ ሖ መ ሙ ሚ ማ ሜ ም ሞ ሠ ሡ ሢ ሣ ሤ ሥ ሦ ረ ሩ ሪ ራ ሬ ር ሮ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሸ ሹ ሺ ሻ ሼ ሽ ሾ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቈ ቊ ቋ ቌ ቍ ቐ ቑ ቒ ቓ ቔ ቕ ቖ ቘ ቚ ቛ ቜ ቝ በ ቡ ቢ ባ ቤ ብ ቦ ቨ ቩ ቪ ቫ ቬ ቭ ቮ ተ ቱ ቲ ታ ቴ ት ቶ ቸ ቹ ቺ ቻ ቼ ች ቾ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኈ ኊ ኋ ኌ ኍ ነ ኑ ኒ ና ኔ ን ኖ ኘ ኙ ኚ ኛ ኜ ኝ ኞ አ ኡ ኢ ኣ ኤ እ ኦ ከ ኩ ኪ ካ ኬ ክ ኮ ኰ ኲ ኳ ኴ ኵ ኸ ኹ ኺ ኻ ኼ ኽ ኾ ዀ ዂ ዃ ዄ ዅ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዠ ዡ ዢ ዣ ዤ ዥ ዦ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ጀ ጁ ጂ ጃ ጄ ጅ ጆ ገ ጉ ጊ ጋ ጌ ግ ጎ ጐ ጒ ጓ ጔ ጕ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጨ ጩ ጪ ጫ ጬ ጭ ጮ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ፀ ፁ ፂ ፃ ፄ ፅ ፆ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፐ ፑ ፒ ፓ ፔ ፕ ፖ [tig] names = Tigre characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሐ ሑ ሒ ሓ ሔ ሕ ሖ መ ሙ ሚ ማ ሜ ም ሞ ረ ሩ ሪ ራ ሬ ር ሮ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሸ ሹ ሺ ሻ ሼ ሽ ሾ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቈ ቊ ቋ ቌ ቍ በ ቡ ቢ ባ ቤ ብ ቦ ተ ቱ ቲ ታ ቴ ት ቶ ቸ ቹ ቺ ቻ ቼ ች ቾ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኈ ኊ ኋ ኌ ኍ ነ ኑ ኒ ና ኔ ን ኖ አ ኡ ኢ ኣ ኤ እ ኦ ከ ኩ ኪ ካ ኬ ክ ኮ ኰ ኲ ኳ ኴ ኵ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዠ ዡ ዢ ዣ ዤ ዥ ዦ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ጀ ጁ ጂ ጃ ጄ ጅ ጆ ገ ጉ ጊ ጋ ጌ ግ ጎ ጐ ጒ ጓ ጔ ጕ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጨ ጩ ጪ ጫ ጬ ጭ ጮ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፐ ፑ ፒ ፓ ፔ ፕ ፖ [tk] names = Turkmen principal-territory = TM [tl] names = Tagalog characters = (ñ) (Ñ) plural-forms = nplurals=2; plural=n > 1; principal-territory = PH [tlh] names = Klingon tlhIngan-Hol [tn] names = Setswana Tswana [to] names = Tonga principal-territory = TO [tpi] names = Tok Pisin [tr] names = Turkish Türkçe characters = ç ğ ı i ö ş ü Ç Ğ I İ Ö Ş Ü plural-forms = nplurals=1; plural=0; nplurals=2; plural=n != 1; principal-territory = TR [ts] names = Tsonga [tt] names = Tatar characters = а ә б в г д е ё ж җ з и й к л м н ң о ө п р с т у ү ф х һ ц ч ш щ ъ ы ь э ю я А Ә Б В Г Д Е Ё Ж Җ З И Й К Л М Н Ң О Ө П Р С Т У Ү Ф Х Һ Ц Ч Ш Щ Ъ Ы Ь Э Ю Я characters@iqtelif = ç ğ ı í ñ ö ş ü Ç Ğ İ Í Ñ Ö Ş Ü [tvl] names = Tuvalu [tw] names = Twi [ty] names = Tahitian [tyv] names = Tuvinian characters = а б в г д е ё ж з и й к л м н ң о ө п р с т у ү ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н Ң О Ө П Р С Т У Ү Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я [ug] names = Uighur Uyghur characters = ا ە ب پ ت ج چ خ د ر ز ژ س ش غ ف ق ك گ ڭ ل م ن ھ و ۇ ۆ ۈ ۋ ې ى ي plural-forms = nplurals=1; plural=0; principal-territory = CN [uk] names = Ukrainian characters = а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ь ю я А Б В Г Ґ Д Е Є Ж З И І Ї Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ь Ю Я plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = UA [ur] names = Urdu characters = ا ب پ ت ٹ ث ج چ ح خ د ڈ ذ ر ڑ ز ژ س ش ص ض ط ظ ع غ ف ق ک گ ل م ن و ہ ھ ء ی ے plural-forms = nplurals=2; plural=n != 1; principal-territory = PK [uz] names = Uzbek characters = oʻ gʻ ʼ Oʻ Gʻ characters@cyrillic = а б д е э ф г ҳ и ж к л м н о п қ р с т у в х й з ў ғ ш ч ъ ё ю я А Б Д Е Э Ф Г Ҳ И Ж К Л М Н О П Қ Р С Т У В Х Й З Ў Ғ Ш Ч Ё Ю Я principal-territory = UZ [ve] names = Venda principal-territory = ZA [vi] names = Vietnamese characters = à ả ã á ạ ă ằ ẳ ẵ ắ ặ â ầ ẩ ẫ ấ ậ đ è ẻ ẽ é ẹ ê ề ể ễ ế ệ ì ỉ ĩ í ị ò ỏ õ ó ọ ô ồ ổ ỗ ố ộ ơ ờ ở ỡ ớ ợ ù ủ ũ ú ụ ư ừ ử ữ ứ ự ỳ ỷ ỹ ý ỵ À Ả à Á Ạ Ă Ằ Ẳ Ẵ Ắ Ặ  Ầ Ẩ Ẫ Ấ Ậ Đ È Ẻ Ẽ É Ẹ Ê Ề Ể Ễ Ế Ệ Ì Ỉ Ĩ Í Ị Ò Ỏ Õ Ó Ọ Ô Ồ Ổ Ỗ Ố Ộ Ơ Ờ Ở Ỡ Ớ Ợ Ù Ủ Ũ Ú Ụ Ư Ừ Ử Ữ Ứ Ự Ỳ Ỷ Ỹ Ý Ỵ plural-forms = nplurals=1; plural=0; principal-territory = VN [vo] names = Volapük characters = ä ö ü Ä Ö Ü [wa] names = Walloon characters = â å ç è é ê î ô û Â Å Ç È É Ê Î Ô Û principal-territory = BE [wal] names = Wolaitta Wolaytta principal-territory = ET [wo] names = Wolof [xh] names = Xhosa plural-forms = nplurals=2; plural=n != 1; [yi] names = Yiddish [yo] names = Yoruba [za] names = Chuang Zhuang [zh] names = Chinese # The list of Chinese ideograms is incomplete; # only the 100 most often used ones are included here. characters = 保 被 本 表 不 部 查 成 程 出 除 此 存 大 到 的 地 定 度 多 法 方 分 改 格 更 工 果 行 和 或 加 件 建 接 可 了 理 列 面 名 模 目 能 您 其 器 前 取 全 如 入 上 生 失 使 始 式 是 示 所 它 提 通 外 位 未 文 系 下 小 效 新 型 需 序 要 一 移 以 已 用 有 在 找 者 正 支 知 值 指 制 置 中 重 主 字 自 最 作 [zh_CN] names = Chinese (simplified) [zh_HK] names = Chinese (Hong Kong) [zh_TW] names = Chinese (traditional) [zu] names = Zulu # vim:ft=dosini i18nspector-0.27.1/data/string-formats0000644000000000000000000000516114275257143017606 0ustar00rootroot00000000000000[formats] # = [example...] awk = %d # https://www.gnu.org/software/gawk/manual/html_node/Printf.html boost = %d # https://www.boost.org/doc/libs/1_68_0/libs/format/doc/format.html c = %d # https://man7.org/linux/man-pages/man3/printf.3.html csharp = {0} # https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting elisp = %d # https://www.gnu.org/software/emacs/manual/html_node/elisp/Formatting-Strings.html gcc-internal = %d # https://www.gnu.org/software/gettext/manual/html_node/gcc_002dinternal_002dformat.html gfc-internal = %d # https://www.gnu.org/software/gettext/manual/html_node/gfc_002dinternal_002dformat.html java = {0} # https://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html # https://ssl.icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html javascript = %d # https://www.gnu.org/software/gettext/manual/html_node/javascript_002dformat.html # https://nodejs.org/api/util.html#util_util_format_format kde = %1 # https://techbase.kde.org/Development/Tutorials/Localization/i18n kde-kuit = %1 # https://api.kde.org/frameworks/ki18n/html/prg_guide.html librep = %d # http://librep.sourceforge.net/librep-manual.html#Formatted%20Output lisp = ~A # http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm lua = %d # https://www.lua.org/manual/5.2/manual.html#pdf-string.format objc = %d # https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html object-pascal = %d # https://www.freepascal.org/docs-html/rtl/sysutils/format.html perl = %d # https://perldoc.perl.org/functions/sprintf.html perl-brace = {var} # https://metacpan.org/pod/Locale::TextDomain php = %d # https://secure.php.net/manual/en/function.sprintf.php python = %d # https://docs.python.org/2/library/stdtypes.html#string-formatting-operations # https://docs.python.org/3/library/stdtypes.html#old-string-formatting python-brace = {0} {var} # https://docs.python.org/2/library/string.html#formatstrings # https://docs.python.org/3/library/string.html#formatstrings qt = %1 # https://doc.qt.io/qt-5/qstring.html#arg qt-plural = %n # https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals scheme = ~A # https://people.csail.mit.edu/jaffer/slib/Format-Specification.html sh = $var # https://www.gnu.org/software/gettext/manual/html_node/sh_002dformat.html smalltalk = %1 # https://www.gnu.org/software/smalltalk/manual-base/html_node/CharacterArray_002dstring-processing.html tcl = %d # https://www.tcl.tk/man/tcl8.6/TclCmd/format.htm ycp = %1 # https://doc.opensuse.org/projects/YaST/SLES11/tdg/sformat.html # vim:ft=dosini i18nspector-0.27.1/data/tags0000644000000000000000000011612014275257143015563 0ustar00rootroot00000000000000[ancient-date] severity = normal certainty = certain description = The date refers to the time before the first GNU gettext release. As such, it's extremely unlikely to be correct. references = https://git.savannah.gnu.org/cgit/gettext.git/tree/ChangeLog.0#n1767 [arithmetic-error-in-plural-forms] severity = serious certainty = possible description = Computing a plural form value triggers division by zero or integer overflow. This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [arithmetic-error-in-unused-plural-forms] severity = normal certainty = possible description = Computing a plural form value triggers division by zero or integer overflow. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [boilerplate-in-content-type] severity = important certainty = certain description = The Content-Type header field contains xgettext boilerplate. It should be in the form ``text/plain; charset=``\ *encoding*. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files [boilerplate-in-date] severity = normal certainty = certain description = The date header field contains xgettext boilerplate. The date format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. [boilerplate-in-initial-comments] severity = minor certainty = possible description = The initial comments contain xgettext or msginit boilerplate. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-language-team] severity = minor certainty = certain description = The Language-Team header field contains xgettext boilerplate. It should contain English name of the language, and the email address or homepage URL of the language team. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-last-translator] severity = normal certainty = certain description = The Last-Translator header field contains xgettext boilerplate. It should contain the last translator's name and email address. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-project-id-version] severity = minor certainty = certain description = The Project-Id-Version header field contains xgettext boilerplate. It should contain the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-report-msgid-bugs-to] severity = normal certainty = certain description = The Report-Msgid-Bugs-To header field contains xgettext boilerplate. It should contain an email address or URL where one can report bugs in the untranslated strings. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [broken-encoding] severity = serious certainty = possible description = Header fields and messages contained by this file couldn't be decoded to Unicode. The usual cause of this is incorrect or missing encoding declaration. . Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files https://tools.ietf.org/html/rfc2045#section-5 [c-format-string-argument-type-mismatch] severity = serious certainty = possible description = There's a type mismatch between a C format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a C format argument in ``msgstr`` and ``msgid``; or between a C format argument in ``msgstr[``\ *N*\ ``]`` and corresponding ``msgid`` or ``msgid_plural``. references = printf(3) https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [c-format-string-error] severity = serious certainty = possible description = A C format string could not be parsed. references = printf(3) [c-format-string-excess-arguments] severity = serious certainty = possible description = A C format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than corresponding ``msgid`` or ``msgid_plural``. references = printf(3) https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [c-format-string-missing-arguments] severity = serious certainty = possible description = A C format string for ``msgid`` consumes fewer arguments than ``msgid_plural``; or ``msgstr`` consumes fewer arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes fewer arguments than corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "%d bytes" . msgstr[0] "%d bajt" . msgstr[1] "%d bajta" . msgstr[2] "%d bajtova" . Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "%d bytes" . msgstr[0] "%d bajt" . msgstr[1] "%d bajta" . msgstr[2] "%d bajtova" . msgstr[3] "jedan bajt" references = printf(3) https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [c-format-string-non-portable-conversion] severity = pedantic certainty = possible description = A C format string uses a conversion specified or length modifier, for which a more portable replacement exists: . * For integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``), use the ``ll`` length modifier instead of ``L`` or ``q``. * For floating-point conversions (``%a``, ``%A``, ``%e``, ``%E``, ``%f``, ``%F``, ``%g``, and ``%G``), don't use the ``l`` length modifier. * Use the ``z`` length modifier instead of ``Z``. * Use ``%lc`` instead of ``%C``. * Use ``%ls`` instead of ``%S``. references = printf(3) [c-format-string-redundant-flag] severity = pedantic certainty = possible description = A C format string includes a redundant character flag. Either it's a duplicate, or it has no effect: . * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). references = printf(3) [codomain-error-in-plural-forms] severity = serious certainty = certain description = Either a plural form value is outside the declared range, or some values within the declared range can never be reached. This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [codomain-error-in-unused-plural-forms] severity = normal certainty = certain description = Either a plural form value is outside the declared range, or some values within the declared range can never be reached. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [conflict-marker-in-header-entry] severity = serious certainty = certain description = The header contains a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. references = https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia [conflict-marker-in-translation] severity = serious certainty = possible description = One of the translated messages appear to contain a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. references = https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia [conflicting-message-flags] severity = important certainty = possible description = Two flags with conflicting meanings are associated with one of the messages. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [date-from-future] severity = normal certainty = certain description = The date refers to the future. As such, it's extremely unlikely to be correct. [distant-header-entry] severity = important certainty = certain description = The header entry in this file is preceded by other entries. The header entry should be always the first one. [duplicate-flag-for-header-entry] severity = minor certainty = certain description = Multiple identical flags are associated with the header entry. [duplicate-header-entry] severity = serious certainty = certain description = This file contains multiple header entries. [duplicate-header-field] severity = minor certainty = wild-guess description = This file contains multiple header fields of the same name. [duplicate-header-field-content-transfer-encoding] severity = pedantic certainty = certain description = This file contains multiple Content-Transfer-Encoding header fields. [duplicate-header-field-content-type] severity = serious certainty = certain description = This file contains multiple Content-Type header fields. [duplicate-header-field-date] severity = normal certainty = certain description = This file contains multiple date header fields of the same name. [duplicate-header-field-language] severity = important certainty = certain description = This file contains multiple Language header fields. [duplicate-header-field-language-team] severity = normal certainty = certain description = This file contains multiple Language-Team header fields. [duplicate-header-field-last-translator] severity = normal certainty = certain description = This file contains multiple Last-Translator header fields. [duplicate-header-field-mime-version] severity = pedantic certainty = certain description = This file contains multiple MIME-Version header fields. [duplicate-header-field-plural-forms] severity = serious certainty = certain description = This file contains multiple Plural-Forms header fields. [duplicate-header-field-project-id-version] severity = minor certainty = certain description = This file contains multiple Project-Id-Version header fields. [duplicate-header-field-report-msgid-bugs-to] severity = normal certainty = certain description = This file contains multiple Report-Msgid-Bugs-To header fields. [duplicate-header-field-x-poedit] severity = normal certainty = certain description = This file contains multiple X-Poedit-*\** header fields. [duplicate-message-definition] severity = serious certainty = certain description = This file contains multiple definitions of the same message. [duplicate-message-flag] severity = minor certainty = certain description = Multiple identical flags are associated with one of the messages. [empty-file] severity = normal certainty = certain description = This file doesn't contain any messages. [empty-msgid-message-with-plural-forms] severity = serious certainty = certain description = The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``ngettext("", …)``. [empty-msgid-message-with-source-code-references] severity = serious certainty = possible description = The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``gettext("")``. [encoding-in-language-header-field] severity = minor certainty = certain description = The language header field contains encoding declaration. Such information shouldn't be included in this field. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [fuzzy-header-entry] severity = pedantic certainty = certain description = The header entry is marked as fuzzy. For compatibility with very old (<< 0.11) **msgfmt**\ (1) versions, which didn't support fuzzy header entries, it shouldn't be marked as such. references = https://git.savannah.gnu.org/cgit/gettext.git/tree/NEWS?id=v0.11#n44 [inconsistent-leading-newlines] severity = important certainty = possible description = Some strings in an entry start with a newline, but some don't. Either all of them should start with a newline, or none of them should. [inconsistent-number-of-plural-forms] severity = serious certainty = certain description = Number of plural forms in a message definition doesn't match number of plural forms declared in another message definition. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [inconsistent-trailing-newlines] severity = important certainty = possible description = Some strings in an entry end with a newline, but some don't. Either all of them should end with a newline, or none of them should. [incorrect-number-of-plural-forms] severity = serious certainty = certain description = Number of plural forms in a message definition doesn't match number of plural forms declared in the header. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [invalid-content-transfer-encoding] severity = pedantic certainty = certain description = Value of the Content-Transfer-Encoding header field is invalid. It should be ``8bit``. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2045#section-6.1 [invalid-content-type] severity = important certainty = possible description = Value of the Content-Type header field should is invalid. It should be in the form ``text/plain; charset=``\ *encoding*. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files https://tools.ietf.org/html/rfc2045#section-5 [invalid-date] severity = normal certainty = certain description = The date is invalid or in an invalid format. The format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [invalid-language] severity = important certainty = possible description = The Language header field couldn't be parsed, or it contains an unknown language. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [invalid-language-team] severity = normal certainty = possible description = The Language-Team header field contains an e-mail address that uses a reserved domain name, or a partially qualified domain name. references = https://tools.ietf.org/html/rfc2606 [invalid-last-translator] severity = normal certainty = possible description = The Last-Translator header field could neither be parsed as an e-mail, or the e-mail address uses a reserved domain name, or a partially qualified domain name. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2606 [invalid-mime-version] severity = pedantic certainty = certain description = Value of the MIME-Version header field is invalid. It should be ``1.0``. references = https://tools.ietf.org/html/rfc2045#section-4 [invalid-mo-file] severity = serious certainty = certain description = This file couldn't be parsed a MO file. [invalid-range-flag] severity = important certainty = certain description = A ``range:`` flag couldn't be parsed, or the designated range contained fewer than two numbers. The syntax is ``range:``\ *min*\ ``..``\ *max*, where both values are non-negative integers. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [invalid-report-msgid-bugs-to] severity = normal certainty = possible description = The Report-Msgid-Bugs-To header field could neither be parsed as an e-mail nor as a URL, or the e-mail address uses a reserved domain name, or a partially qualified domain name. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2606 [language-disparity] severity = normal certainty = possible description = Language of this file has been declared in multiple places, but the declarations don't match. [language-team-equal-to-last-translator] severity = minor certainty = possible description = Language-Team and Last-Translator header fields contain the same e-mail address. [language-variant-does-not-affect-translation] severity = minor certainty = possible description = The Language header field contains a variant designator that is not relevant for the message translation. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [leading-junk-in-plural-forms] severity = important certainty = certain description = The Plural-Forms header field contains unexpected text before the ``nplurals=`` string. . GNU gettext runtime ignores such leading junk, but other header parsers might be less liberal in what they accept. [malformed-xml] severity = serious certainty = possible description = The original string or the translated string contains an XML fragment, which is not well-formed. references = https://www.w3.org/TR/REC-xml/#sec-well-formed [no-content-transfer-encoding-header-field] severity = pedantic certainty = certain description = The Content-Transfer-Encoding header field doesn't exist. It should be set to ``8bit``. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2045#section-6.1 [no-content-type-header-field] severity = important certainty = certain description = The Content-Type header field doesn't exist. It should be set to ``text/plain; charset=``\ *encoding*. . Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files https://tools.ietf.org/html/rfc2045#section-5 [no-date-header-field] severity = minor certainty = certain description = The date header field doesn't exist. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-language-header-field] severity = pedantic certainty = certain description = The Language header field doesn't exist. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-language-team-header-field] severity = pedantic certainty = certain description = The Language-Team header field does not exist. It should contain English name of the language, and the email address or homepage URL of the language team. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-last-translator-header-field] severity = normal certainty = certain description = The Last-Translator header field doesn't exist. It should contain the last translator's name and email address. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-mime-version-header-field] severity = pedantic certainty = certain description = The MIME-Version header field doesn't exist. It should be to set to ``1.0``. references = https://tools.ietf.org/html/rfc2045#section-4 [no-package-name-in-project-id-version] severity = minor certainty = possible description = The Project-Id-Version header field doesn't appear to contain any name. It should contain both the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-plural-forms-header-field] severity = minor certainty = certain description = The Plural-Forms header field does not exist, even though some of the messages use plural forms (although none of them have been translated). references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [no-project-id-version-header-field] severity = minor certainty = certain description = The Project-Id-Version header field does not exist. It should contain the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-report-msgid-bugs-to-header-field] severity = normal certainty = certain description = The Report-Msgid-Bugs-To header field does not exist or it is empty. It should contain an email address or URL where one can report bugs in the untranslated strings. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-required-plural-forms-header-field] severity = serious certainty = certain description = The Plural-Forms header field does not exist, even though some of the translated messages use plural forms. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [no-version-in-project-id-version] severity = pedantic certainty = possible description = The Project-Id-Version header field doesn't appear to contain any version. It should contain both the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [non-ascii-compatible-encoding] severity = serious certainty = certain description = This file uses an encoding that is not compatible with ASCII. [non-portable-encoding] severity = important certainty = certain description = This file uses an encoding that is not widely supported by software. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-list [os-error] severity = serious certainty = certain description = An input/output error or another operating system error occurred while checking this file. [partially-translated-message] severity = serious certainty = possible description = Translation is missing for some plural forms of a message. [perl-brace-format-string-error] severity = serious certainty = possible description = A Perl format string could not be parsed. references = https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html [perl-brace-format-string-missing-argument] severity = serious certainty = possible description = A Perl format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "{n} bytes" . msgstr[0] "{n} bajt" . msgstr[1] "{n} bajta" . msgstr[2] "{n} bajtova" . Here ``{n}`` should not be replaced with the spelled-out form ``jedan``. Either ``{n}`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "{n} bytes" . msgstr[0] "{n} bajt" . msgstr[1] "{n} bajta" . msgstr[2] "{n} bajtova" . msgstr[3] "jedan bajt" references = https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [perl-brace-format-string-unknown-argument] severity = serious certainty = possible description = A Perl format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. references = https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [python-brace-format-string-argument-type-mismatch] severity = serious certainty = possible description = There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. references = https://docs.python.org/2/library/string.html#formatstrings [python-brace-format-string-error] severity = serious certainty = possible description = A Python format string could not be parsed. references = https://docs.python.org/2/library/string.html#formatstrings [python-brace-format-string-missing-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "{n} bytes" . msgstr[0] "{n} bajt" . msgstr[1] "{n} bajta" . msgstr[2] "{n} bajtova" . Here ``{n}`` should not be replaced with the spelled-out form ``jedan``. Either ``{n}`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "{n} bytes" . msgstr[0] "{n} bajt" . msgstr[1] "{n} bajta" . msgstr[2] "{n} bajtova" . msgstr[3] "jedan bajt" references = https://docs.python.org/2/library/string.html#formatstrings https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [python-brace-format-string-unknown-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. references = https://docs.python.org/2/library/string.html#formatstrings https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [python-format-string-argument-number-mismatch] severity = serious certainty = possible description = A Python format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than ``msgid`` or ``msgid_plural``. . Python, unlike C, requires that all unnamed arguments must be consumed during conversion. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python [python-format-string-argument-type-mismatch] severity = serious certainty = possible description = There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-error] severity = serious certainty = possible description = A Python format string could not be parsed. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-missing-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "%(n)d bytes" . msgstr[0] "%(n)d bajt" . msgstr[1] "%(n)d bajta" . msgstr[2] "%(n)d bajtova" . Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "%(n)d bytes" . msgstr[0] "%(n)d bajt" . msgstr[1] "%(n)d bajta" . msgstr[2] "%(n)d bajtova" . msgstr[3] "jedan bajt" references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [python-format-string-multiple-unnamed-arguments] severity = serious certainty = possible description = A Python format string uses multiple unnamed arguments (such as ``%d``). The translator might need to reorder the arguments to properly translate the message, but this is not possible with unnamed arguments. Named arguments (such as ``%(num)d``) should be used instead. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python [python-format-string-obsolete-conversion] severity = pedantic certainty = possible description = A Python format string uses an obsolete conversion specifier: . * Use ``%d`` instead of ``%u``. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-redundant-flag] severity = pedantic certainty = possible description = A Python format string includes a redundant character flag. Either it's a duplicate, or it has no effect: . * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-redundant-length] severity = pedantic certainty = possible description = A Python format string includes a redundant length modifier. Length modifiers (``h``, ``l``, or ``L``) have no effect in Python. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-redundant-precision] severity = pedantic certainty = possible description = A C format string includes precision that has no effect on the conversion. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-unknown-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [python-format-string-unnamed-plural-argument] severity = wishlist certainty = possible description = A Python format string uses an unnamed arguments (such as ``%d``) in the context of plural forms. The translator might want not to use the numeric argument in the singular form; but this is not possible if the argument is unnamed, because Python, unlike C, requires that all unnamed arguments must be consumed during conversion. Named arguments (such as ``%(n)d``) should be used instead. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python [qt-plural-format-mistaken-for-c-format] severity = important certainty = possible description = A ``c-format`` flag is associated with the message, but ``qt-plural-format`` should be used instead. . The only C format directive that the message uses is ``%n``. It is very atypical to use it alone in a C format string. references = https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals printf(3) [range-flag-without-plural-string] severity = normal certainty = certain description = A ``range:`` flag is associated with a message that doesn't have plural string. ``range:`` flags only make sense for translations involving plural forms. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [redundant-message-flag] severity = pedantic certainty = certain description = A flag associated with one of the messages is redundant, because it's implied by another flag. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [stray-header-line] severity = important certainty = certain description = The header contains a line that does not belong to any header field. Note that RFC-822-style folding of long headers is not supported. references = https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html [stray-previous-msgid] severity = minor certainty = certain description = The message entry contains annotations about previous untranslated string (``#| msgid``\ *...*), even though the message is not marked as fuzzy. These annotations are only useful for fuzzy messages, and should be removed when unfuzzying. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [syntax-error-in-plural-forms] severity = serious certainty = certain description = Value of the Plural-Forms header field could not be parsed. It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [syntax-error-in-po-file] severity = serious certainty = possible description = This file couldn't be parsed a PO file. In some rare cases this is due to incorrect or missing encoding declaration. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html https://bugs.debian.org/692283 [syntax-error-in-unused-plural-forms] severity = important certainty = certain description = Value of the Plural-Forms header field could not be parsed. (But there are no translated messages which use plural forms.) It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [trailing-junk-in-plural-forms] severity = important certainty = certain description = The Plural-Forms header field contains unexpected text after the plural expression. . GNU gettext runtime ignores such trailing junk, but other header parsers might be less liberal in what they accept. [translation-in-template] severity = minor certainty = certain description = The PO template file contains a translated message. [unable-to-determine-language] severity = normal certainty = wild-guess description = i18nspector was unable to determine language of this file. Absence of this information will prevent it from performing further checks. [unexpected-flag-for-header-entry] severity = normal certainty = possible description = An unexpected flag is associated with the header entry. The only flag that makes sense for the header entry is ``fuzzy``. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [unknown-encoding] severity = important certainty = possible description = This file declares an encoding that couldn't be recognized by i18nspector. It might be a typo. Absence of encoding information will prevent i18nspector from performing further checks. [unknown-file-type] severity = normal certainty = wild-guess description = File format of this file couldn't be recognized. It might be a bug in i18nspector. [unknown-header-field] severity = minor certainty = wild-guess description = The header field name is unknown to i18nspector. It might be a typo or a capitalization error (header field names are case-sensitive). references = https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html [unknown-message-flag] severity = normal certainty = wild-guess description = An unknown flag is associated with one of the messages. It might be a typo. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [unknown-poedit-language] severity = minor certainty = wild-guess description = Language declared in X-Poedit-Language couldn't be recognized. It might be a bug in i18nspector. [unrepresentable-characters] severity = serious certainty = possible description = The declared encoding cannot represent all characters commonly used in this language. This is a strong indication that the declared encoding is incorrect. [unusual-character-in-header-entry] severity = important certainty = certain description = The header entry contains an unusual character. This is usually an indication of an encoding problem, such as: . * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. references = https://www.unicode.org/faq/utf_bom.html#bom6 [unusual-character-in-translation] severity = important certainty = possible description = One of the translated messages contains an unusual character. This is usually an indication of an encoding problem, such as: . * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. references = https://www.unicode.org/faq/utf_bom.html#bom6 [unusual-plural-forms] severity = serious certainty = possible description = The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. [unusual-unused-plural-forms] severity = normal certainty = possible description = The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. (But there are no translated messages which use plural forms.) # vim:ft=dosini i18nspector-0.27.1/data/timezones0000644000000000000000000000615514275257143016650 0ustar00rootroot00000000000000# This file has been generated automatically by private/update-timezones. # Do not edit. # Timezone database version: 2014e # Last update: 2014-07-07 [timezones] ACT = -0500 ADT = +0400 -0300 AFT = +0430 AKDT = -0800 AKST = -0900 ALMST = +0700 ALMT = +0600 AMST = +0400 +0500 -0300 AMT = +0300 +0400 -0400 ANAST = +1200 +1300 ANAT = +1100 +1200 AQTST = +0500 +0600 AQTT = +0400 +0500 ARST = -0200 -0300 ART = -0300 AST = +0300 -0400 AZOST = +0000 AZOT = -0100 AZST = +0500 AZT = +0400 BDST = +0700 BDT = +0600 BNT = +0800 BOT = -0400 BRST = -0200 BRT = -0300 BST = +0100 BTT = +0600 CAST = +1100 CAT = +0200 CCT = +0630 CDT = -0400 -0500 CEST = +0200 CET = +0100 CHADT = +1345 CHAST = +1245 CHOST = +1000 CHOT = +0800 +0900 CHUT = +1000 CKT = -1000 CLST = -0300 CLT = -0400 COT = -0500 CST = +0800 +0930 +1030 -0500 -0600 CVT = -0100 CWST = +0845 +0945 CXT = +0700 ChST = +1000 DAVT = +0500 +0700 DDUT = +1000 EASST = -0500 EAST = -0600 EAT = +0300 ECT = -0500 EDT = -0400 EEST = +0300 EET = +0200 EGST = +0000 EGT = -0100 EST = +1000 +1100 -0500 FET = +0300 FJST = +1300 FJT = +1200 FKST = -0300 FKT = -0400 FNST = -0100 FNT = -0200 GALT = -0600 GAMT = -0900 GEST = +0400 +0500 GET = +0300 +0400 GFT = -0300 GILT = +1200 GMT = +0000 GST = +0400 +1000 -0200 GYT = -0400 HADT = -0900 HAST = -1000 HKT = +0800 HOVST = +0800 HOVT = +0700 HST = -1000 ICT = +0700 IDT = +0300 IOT = +0500 +0600 IRDT = +0430 IRKST = +0900 IRKT = +0800 +0900 IRST = +0330 IST = +0100 +0200 +0530 JST = +0900 KGST = +0600 KGT = +0500 +0600 KOST = +1100 +1200 KRAST = +0800 KRAT = +0700 +0800 KST = +0900 LHST = +1030 +1100 LINT = +1400 -1000 LKT = +0600 +0630 MAGST = +1200 MAGT = +1100 +1200 MART = -0930 MAWT = +0500 +0600 MDT = -0600 MEST = +0200 MET = +0100 MHT = +1200 MIST = +1100 MMT = +0630 MOT = +0800 MPT = +1000 MSD = +0400 MSK = +0300 +0400 MST = -0700 MUST = +0500 MUT = +0400 MVT = +0500 MYT = +0800 MeST = -0800 NCST = +1200 NCT = +1100 NDT = -0230 NFT = +1130 NOVST = +0700 NOVT = +0600 +0700 NPT = +0545 NRT = +1200 NST = -0330 NUT = -1100 NZDT = +1300 NZST = +1200 OMSST = +0700 OMST = +0600 +0700 ORAST = +0500 ORAT = +0400 +0500 PDT = -0700 PET = -0500 PETST = +1200 +1300 PETT = +1100 +1200 PGT = +1000 PHOT = +1300 -1100 PHT = +0800 PKST = +0600 PKT = +0500 PMDT = -0200 PMST = -0300 PNT = -0830 PONT = +1100 PST = -0800 PWT = +0900 PYST = -0300 PYT = -0400 QYZST = +0700 QYZT = +0600 RET = +0400 ROTT = -0300 SAKST = +1100 +1200 SAKT = +1000 +1100 SAMST = +0400 +0500 SAMT = +0300 +0400 SAST = +0200 SBT = +1100 SCT = +0400 SGT = +0800 SRT = -0300 SST = -1100 SYOT = +0300 TAHT = -1000 TFT = +0500 TJT = +0500 TKT = +1300 -1100 TLT = +0900 TMT = +0500 TOST = +1400 TOT = +1300 TVT = +1200 UCT = +0000 ULAST = +0900 ULAT = +0800 UTC = +0000 UYST = -0200 UYT = -0300 UZT = +0500 VET = -0400 -0430 VLAST = +1100 VLAT = +1000 +1100 VOLST = +0400 VOLT = +0300 +0400 VOST = +0600 VUT = +1100 WAKT = +1200 WARST = -0300 WART = -0400 WAST = +0200 WAT = +0100 WEST = +0100 WET = +0000 WFT = +1200 WGST = -0200 WGT = -0300 WIB = +0700 WIT = +0900 WITA = +0800 WSDT = +1400 -1000 WST = +0800 +0900 +1300 -1100 YAKST = +1000 YAKT = +0900 +1000 YEKST = +0600 YEKT = +0500 +0600 # vim:ft=dosini i18nspector-0.27.1/doc/0000755000000000000000000000000014275257160014534 5ustar00rootroot00000000000000i18nspector-0.27.1/doc/LICENSE0000644000000000000000000000207414275257143015545 0ustar00rootroot00000000000000Copyright © 2012-2022 Jakub Wilk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. i18nspector-0.27.1/doc/Makefile0000644000000000000000000000354714275257143016206 0ustar00rootroot00000000000000# Copyright © 2012-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. export LC_ALL=C rst2man = $(notdir $(shell command -v rst2man || echo rst2man.py)) exe = i18nspector .PHONY: all all: $(exe).1 tags.rst: ../data/tags ../private/tags-as-rst > $(@).tmp mv $(@).tmp $(@) $(exe).1: manpage.rst tags.rst $(rst2man) --input-encoding=UTF-8 < $(<) > $(@).tmp perl -pi -e '/^[.]BI\b/ and s/\\fP/\\fR/g' $(@).tmp # work-around for https://bugs.debian.org/806601 perl -pi -e 's/^[.]de1\b/.de/' $(@).tmp # work-around for https://bugs.debian.org/710678 perl -pi -e 's/([a-z])\\[(]aq([a-z])/$$1\x27$$2/g' $(@).tmp # prefer ' to \(aq when used as an apostrophe perl -ni -e 'print unless /^[.]\\" vim:/' $(@).tmp mv $(@).tmp $(@) .PHONY: clean clean: rm -f tags.rst $(exe).1 *.tmp .error = GNU make is required # vim:ts=4 sts=4 sw=4 noet i18nspector-0.27.1/doc/README0000644000000000000000000000170214275257143015415 0ustar00rootroot00000000000000Overview ======== **i18nspector** is a tool for checking translation templates (POT), message catalogues (PO) and compiled message catalogues (MO) files for common problems. These files are used by the GNU gettext translation functions and tools in many different development environments. Prerequisites ============= The following software is needed to run i18nspector: * Python ≥ 3.6; * polib_ ≥ 1.0.0, a gettext catalogs manipulation library; * RPLY_, a parser generator. Additionally, the following software is needed to rebuild the manual page from source: * docutils_ ≥ 0.6. For pip users:: python3 -m pip install polib rply python3 -m pip install docutils For Debian users:: apt-get install python3-polib python3-rply apt-get install python3-docutils .. _polib: https://pypi.org/project/polib/ .. _RPLY: https://pypi.org/project/rply/ .. _docutils: https://docutils.sourceforge.io/ .. vim:ft=rst ts=3 sts=3 sw=3 i18nspector-0.27.1/doc/changelog0000644000000000000000000010121114275257143016403 0ustar00rootroot00000000000000i18nspector (0.27.1) unstable; urgency=low * Use uppercase for metavars in the help message. * Improve the test suite. + Make it possible to use pytest as the test harness. Thanks to Stuart Prescott for the bug report and the initial patches. https://github.com/jwilk/i18nspector/issues/7 + Skip glibc-supported C.* locales. https://github.com/jwilk/i18nspector/issues/13 -- Jakub Wilk Thu, 11 Aug 2022 21:53:57 +0200 i18nspector (0.27) unstable; urgency=low * Recognize the “markdown-text” message flag. Thanks to intrigeri for the bug report. https://github.com/jwilk/i18nspector/issues/11 * Drop support for Python < 3.6. * Make “-j auto” take CPU affinity into account. * Stop using deprecated abc.abstractproperty(). * Improve documentation: + Update Docutils homepage URL. -- Jakub Wilk Wed, 22 Jun 2022 22:09:41 +0200 i18nspector (0.26) unstable; urgency=low * Summary of tag changes: + Added: - perl-brace-format-string-error - perl-brace-format-string-missing-argument - perl-brace-format-string-unknown-argument * Check for errors in Perl brace format strings. https://github.com/jwilk/i18nspector/issues/6 -- Jakub Wilk Sat, 26 Sep 2020 18:25:06 +0200 i18nspector (0.25.9) unstable; urgency=low * Drop support for Python < 3.4. * Fix compatibility with Python 3.9. https://bugs.python.org/issue39337 * Fix spelling and grammar in tag descriptions. * Improve the test suite. -- Jakub Wilk Thu, 06 Aug 2020 10:22:52 +0200 i18nspector (0.25.8) unstable; urgency=low * Fix compatibility with Python 3.8. https://bugs.python.org/issue32892 * Add writing system information for Maltese. * Rephrase help messages for --help, --version. * Improve error handling. * Improve the test suite. -- Jakub Wilk Thu, 21 Feb 2019 22:23:17 +0100 i18nspector (0.25.7) unstable; urgency=low * Drop support for Python < 3.3.3. + Fix “FutureWarning: Possible nested set” warnings. Thanks to Helge Kreutzmann for the bug report. https://bugs.debian.org/916928 https://bugs.python.org/issue30349 * Improve the build system: + Remove the coverage file when cleaning. + Use install(1) to install the executable. + Use ginstall(1), instead of install(1), if it exists. + Add checks against BSD make. (Only GNU make is supported.) + Byte-compile Python code on install. * Improve documentation: + Use HTTPS for doc.qt.io. + Use HTTPS for www.unicode.org. -- Jakub Wilk Thu, 20 Dec 2018 20:02:15 +0100 i18nspector (0.25.6) unstable; urgency=low * Drop support for Python 3.2. * Update various URLs: + Use HTTPS for savannah.gnu.org. + Use HTTPS for unicode.org. + pypi.python.org → pypi.org. + sources.debian.net → sources.debian.org. + Alioth VCS → sources.debian.org. * Improve the test suite. -- Jakub Wilk Fri, 18 May 2018 22:02:55 +0200 i18nspector (0.25.5) unstable; urgency=low * Don't complain about POT-Creation-Date missing in MO files. In the future versions of gettext (>> 0.19.8.1), msgfmt will be removing the POT-Creation-Date header. https://savannah.gnu.org/bugs/?49654 * Improve error handling. -- Jakub Wilk Tue, 22 Aug 2017 21:21:13 +0200 i18nspector (0.25.4) unstable; urgency=low * Fix crash when checking Python brace formats string that have both named and numbered arguments. * Reorder sections in the manual page, as per man-pages(7) recommendations. * Put license into a separate file. -- Jakub Wilk Fri, 23 Jun 2017 18:25:35 +0200 i18nspector (0.25.3) unstable; urgency=low * Rewrite shebang at install time. Thanks to Kyrill Detinov for the bug report. https://github.com/jwilk/i18nspector/issues/1 -- Jakub Wilk Mon, 29 Aug 2016 13:25:33 +0200 i18nspector (0.25.2) unstable; urgency=low * Don't disable stdout line buffering. * Make --version print also versions of Python and the libraries. * Make --version print to stdout, not stderr. https://bugs.python.org/issue18920 * Use /usr/bin/env in shebangs. * Fix compatibility with PyPy 3. * Improve documentation about dependencies. * Improve the test suite. -- Jakub Wilk Sun, 21 Aug 2016 21:33:49 +0200 i18nspector (0.25.1) unstable; urgency=low * Fix compatibility with Python 3.6. -- Jakub Wilk Thu, 16 Jun 2016 11:27:08 +0200 i18nspector (0.25) unstable; urgency=low * Rename --parallel as -j/--jobs. * Make it possible to specify “auto” as the number of processes to use. * Remove empty lines between references in the manual page. * Improve the test suite. -- Jakub Wilk Tue, 31 May 2016 17:24:25 +0200 i18nspector (0.24) unstable; urgency=low * Summary of tag changes: + Added: - python-brace-format-string-argument-type-mismatch - python-brace-format-string-error - python-brace-format-string-missing-argument - python-brace-format-string-unknown-argument * Check for errors in Python brace format strings. * Raise certainty of syntax-error-in-plural-forms and syntax-error-in-unused-plural-forms to “certain”. (The main reason the certainty was only “possible” is that the tag was also triggered by leading and trailing junk, for which there are separate tags since 0.23.) * Check for partially qualified domain names in e-mail addresses. * Add option for parallel execution (--parallel). * Improve the test suite. -- Jakub Wilk Wed, 24 Feb 2016 16:46:20 +0100 i18nspector (0.23) unstable; urgency=low * Summary of tag changes: + Added: - leading-junk-in-plural-forms - trailing-junk-in-plural-forms * Make separate tags for leading and trailing junk in Plural-Forms. * Fix typos in tag descriptions. * Use HTTPS for more URLs. -- Jakub Wilk Sat, 06 Feb 2016 15:15:26 +0100 i18nspector (0.22) unstable; urgency=low * Summary of tag changes: + Renamed: - unusual-plural-forms (from incorrect-plural-forms) - unusual-unused-plural-forms (from incorrect-unused-plural-forms) * Fix typo in a tag description. * Fix typo in the help message. * Update QT documentation URLs. * Fix option formatting in the manual page. * Remove redundant parentheses from some exemplary Plural-Forms. * Improve plural forms codomain checks. -- Jakub Wilk Thu, 21 Jan 2016 21:58:52 +0100 i18nspector (0.21) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-initial-comments * Check for xgettext and msginit boilerplate in initial comments. * Improve error handling. * Improve the test suite. -- Jakub Wilk Thu, 19 Nov 2015 19:20:40 +0100 i18nspector (0.20.1) unstable; urgency=low * Set up temporary cache directory in tests/run-tests. -- Jakub Wilk Tue, 15 Sep 2015 17:38:38 +0200 i18nspector (0.20) unstable; urgency=low * Use RPLY for parsing plural expressions. This should make the parser more robust. * Improve the test suite. -- Jakub Wilk Thu, 10 Sep 2015 21:45:40 +0200 i18nspector (0.19) unstable; urgency=low * Summary of tag changes: + Added: - python-format-string-argument-number-mismatch - python-format-string-argument-type-mismatch - python-format-string-error - python-format-string-missing-argument - python-format-string-multiple-unnamed-arguments - python-format-string-obsolete-conversion - python-format-string-redundant-flag - python-format-string-redundant-length - python-format-string-redundant-precision - python-format-string-unknown-argument - python-format-string-unnamed-plural-argument * Check for errors in Python format strings. * Add “kde-kuit” as a known string format. * Verify that polib version is sufficiently new. * Fix language-team-equal-to-last-translator when there are multiple Last-Translator fields. * Improve descriptions of a few tags. * Improve the test suite. -- Jakub Wilk Mon, 06 Jul 2015 20:29:22 +0200 i18nspector (0.18.1) unstable; urgency=low * Make the plural expression parser more robust. * Improve the test suite. -- Jakub Wilk Mon, 02 Mar 2015 12:25:43 +0100 i18nspector (0.18) unstable; urgency=low * Rename --debian as --unpack-deb. Don't make it default even on Debian(-like) systems. * Make the plural expression parser more robust. * Improve the test suite. -- Jakub Wilk Tue, 27 Jan 2015 23:24:53 +0100 i18nspector (0.17.2) unstable; urgency=low * Fix parsing Language header fields containing commas. * Document -h/--help and --version in the manual page. * Improve the test suite. -- Jakub Wilk Wed, 19 Nov 2014 15:11:06 +0100 i18nspector (0.17.1) unstable; urgency=low * Restore compatibility with polib 1.0.3 and earlier versions. Thanks to Kyrill Detinov for the bug report. * Improve the test suite. -- Jakub Wilk Sat, 18 Oct 2014 17:19:17 +0200 i18nspector (0.17) unstable; urgency=low * Summary of tag changes: + Added: - malformed-xml * Check syntax of PO4A XML fragments. * Check for duplicate or conflicting “range” flags. * Tighten the check for invalid “range” flags. * Make URLs for the Content-Type header field documentation more precise. * Improve the test suite. -- Jakub Wilk Fri, 26 Sep 2014 22:25:14 +0200 i18nspector (0.16) unstable; urgency=low * Summary of tag changes: + Added: - c-format-string-missing-arguments - qt-plural-format-mistaken-for-c-format - stray-previous-msgid * Check for C format strings in msgstr/msgstr_plural[N] consuming fewer arguments than corresponding msgid/msgid_plural. Thanks to Guillem Jover for the bug report. https://bugs.debian.org/753946 * Check for previous msgid annotations (“#| msgid …”) attached to non-fuzzy messages. * Check for plural Qt format string mistakenly tagged as C format strings. * Temper checks for conflicting and redundant message flags: + Don't complain about two different format flags applied to the same message when the formats compatible are (to some extent) compatible. + Don't complain when a positive format flag (-format) and a negative format flag (no--format) apply to the same message. The negative format flag might be still a useful hint for the translator. * Never consider non-ASCII characters and control-characters as part of C format string conversion. * Don't complain about unknown header fields starting with lowercase “x-”. * Improve descriptions of a few tags. * Improve the test suite. -- Jakub Wilk Fri, 22 Aug 2014 19:22:47 +0200 i18nspector (0.15) unstable; urgency=low * Summary of tag changes: + Added: - c-format-string-argument-type-mismatch - c-format-string-error - c-format-string-excess-arguments - c-format-string-non-portable-conversion - c-format-string-redundant-flag - partially-translated-message * Check for errors in C format strings. * Check for inconsistent leading/trailing newlines in translations even when encoding is unknown or broken. * Check for conflict markers in translations even when encoding is unknown or broken. * Check for incomplete translations in messages with plural forms. * Fix calculation of current time. * When emitting unusual-character-in-translation, don't output the translated string (which is likely to contain mojibake), but only the message identifier. * Suggest using “-0000” (rather than “+0000”) to indicate that the offset to local time is unknown. This convention is inspired by RFC 3339 §4.3 and RFC 5322 §3.3. * Improve the test suite. -- Jakub Wilk Fri, 08 Aug 2014 23:00:29 +0200 i18nspector (0.14) unstable; urgency=low * Summary of tag changes: + Added: - translation-in-template * Check for PO template files containing translated messages. * Check for duplicate messages, for problems with message flags, and for empty files even when encoding is unknown or broken. * Check for inconsistent leading/trailing newlines between msgid and msgid_plural even when encoding is unknown or broken. * Improve the test suite. -- Jakub Wilk Wed, 16 Jul 2014 15:28:40 +0200 i18nspector (0.13.5) unstable; urgency=low * Use HTTPS URLs when they are available, in documentation and code. * Don't complain about conflict markers in fuzzy messages. Thanks to Guillem Jover for the bug report. https://bugs.debian.org/753924 -- Jakub Wilk Mon, 07 Jul 2014 15:01:31 +0200 i18nspector (0.13.4) unstable; urgency=low * Regenerate the timezone information file using tzdata 2014a. * Recognize “8859-n” (without the “ISO-” prefix) as encoding names. * Recognize *.local, *.in-addr.arpa and *.ip6.arpa as special domain names. * Fix compatibility with polib 1.0.4. https://bugs.debian.org/742162 * Improve the test suite. -- Jakub Wilk Thu, 20 Mar 2014 13:54:53 +0100 i18nspector (0.13.3) unstable; urgency=low * Fix incorrect plural expression codomain evaluation. * Fix incorrect precedence of the boolean not operator in plural expressions. * Forbid unary plus and unary minus in plural expressions. * Improve the test suite. -- Jakub Wilk Mon, 20 Jan 2014 20:04:22 +0100 i18nspector (0.13.2) unstable; urgency=low * Reject early encodings that are not compatible with ASCII. https://bugs.python.org/issue19619 * Improve the test suite. -- Jakub Wilk Thu, 02 Jan 2014 13:30:16 +0100 i18nspector (0.13.1) unstable; urgency=low * Fix test failures with Python 3.4. * Fix stripping delay annotations from terminfo capabilities. * Improve the test suite. -- Jakub Wilk Mon, 09 Dec 2013 09:11:05 +0100 i18nspector (0.13) unstable; urgency=low * Summary of tag changes: + Added: - conflicting-message-flags - duplicate-message-flag - invalid-range-flag - range-flag-without-plural-string - redundant-message-flag - unknown-message-flag * Check for duplicate, conflicting, redundant, or unknown message flags. * Strip leading and trailing spaces from flag lines. * Be verbose when checking for messages with empty msgid with source code references. * Reduce duplicate-flag-for-header-entry severity to minor. * Check for zero width no-break space (U+FEFF) in translations and header entries. * Improve the test suite. * Work around a trailing comment parsing bug in polib. https://bitbucket.org/izi/polib/issues/51 -- Jakub Wilk Wed, 11 Sep 2013 14:00:20 +0200 i18nspector (0.12) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-date [ Jakub Wilk ] * Don't emit empty-file for MO files with only system-dependent messages, or with minor revision greater than 1. * Don't emit no-package-name-in-project-id-version if the package name consists of only non-ASCII letters. * Fix parsing some atypical PO comments. * Parse more date formats. * Check for xgettext boilerplate in dates. * Strip trailing whitespace when parsing header entry. * Allow only tabs and spaces between “nplurals=…” and “plural=…”. * Remove Bihari (codes “bh”, “bih”) from the data files; it's not a single language, but a language collection. * Implement 8-bit encodings without iconv(3) or iconv(1). * Add “SEE ALSO” section to the manual page. * Improve the test suite. * Improve the makefile: + Add “clean” target. + Make it possible to use a custom install(1) implementation for “make install”. (This is useful for systems such as FreeBSD which have GNU install available under the name “ginstall”.) + Fix compatibility with find(1) implementations that require a path argument. [ Christopher Meng ] * Makefile: preserve file timestamps. -- Jakub Wilk Fri, 26 Jul 2013 14:18:37 +0200 i18nspector (0.11.1) unstable; urgency=low * Fix the MO file parser: + Detect encoding by inspecting only the first message with empty msgid. + Fix compatibility with Python 3.3. Thanks to Kyrill Detinov for the bug report. * Use the custom MO file encoding detection method rather than the provided by polib. -- Jakub Wilk Mon, 24 Jun 2013 20:28:58 +0200 i18nspector (0.11) unstable; urgency=low * Summary of tag changes: + Added: - distant-header-entry - duplicate-flag-for-header-entry - duplicate-header-entry - duplicate-header-field-x-poedit - empty-msgid-message-with-plural-forms - empty-msgid-message-with-source-code-references - unexpected-flag-for-header-entry - unusual-character-in-header-entry * Fix letter codes for tags with severity important. * Reduce severity of arithmetic-error-in-unused-plural-forms, codomain-error-in-unused-plural-forms, and incorrect-unused-plural-forms to normal. * Implement custom header parser for PO files, and custom MO file parser. (The ones in polib are inadequate for i18nspector's purposes.) * Check for duplicate header entries. * Check for unusually located header entries. * Overhaul handling of duplicates and stray lines in the header entry. + Emit duplicate-header-field-x-poedit (instead of the generic duplicate-header-field) for duplicate X-Poedit-Language and X-Poedit-Country headers fields. * Work around a flag parsing bug in polib. https://bitbucket.org/izi/polib/issues/46 * Check for duplicate and unexpected flags for header entries. * Check for unusual characters in header entries. * Check for messages with empty msgid (header entries?) with source code references or plural forms. * Fix some false-positive language-disparity when PO basename does not designate translation language. * Fix the no-report-msgid-bugs-to-header-field description. * Fix a few typos in the tag descriptions. * Improve the test suite. + Add new tests. + Use a dedicated nose plugin for blackbox tests. -- Jakub Wilk Sun, 23 Jun 2013 22:42:43 +0200 i18nspector (0.10) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-content-type - conflict-marker-in-header-entry - conflict-marker-in-translation - duplicate-header-field-content-transfer-encoding - duplicate-header-field-content-type - duplicate-header-field-date - duplicate-header-field-language - duplicate-header-field-language-team - duplicate-header-field-last-translator - duplicate-header-field-mime-version - duplicate-header-field-plural-forms - duplicate-header-field-project-id-version - duplicate-header-field-report-msgid-bugs-to - fuzzy-header-entry * Check for boilerplate (“charset=CHARSET”) in the Content-Type header field. * Check header field name syntax. * Overhaul duplicate header field detection. + Emit duplicate-header-field only for non-standard fields. Downgrade duplicate-header-field to minor/wild-guess. + Emit duplicate-header-field-$NAME for standard fields. + Don't trust values of standard header fields if duplicates exist. * Check for conflict markers (“#-#-#-#-# … #-#-#-#-#”). * Check for fuzzy header entries. * Fix a typo in the language-team-equal-to-last-translator description. * Post-process the manual page, so that it can be more easily translated by po4a. * If iconv(3) is available in the C standard library, use it to implement encodings that are not implemented in the Python standard library. * Don't pass -s to iconv(1); it makes GNU iconv quieten errors, and other implementations don't have this option at all. * Improve the test suite: + Add new tests. + Make exception messages raised when a subprocess fails more readable. + Make it possible to use a custom Python interpreter for “make test”. -- Jakub Wilk Sat, 15 Jun 2013 17:37:22 +0200 i18nspector (0.9.2) unstable; urgency=low * When emitting broken-encoding, don't output the whole file, but only the undecodable bytes in a small context. -- Jakub Wilk Sat, 08 Jun 2013 11:40:23 +0200 i18nspector (0.9.1) unstable; urgency=low * Brown paper bag release. * Don't complain about leading/trailing newlines in fuzzy messages. Thanks to Guillem Jover for the bug report. https://bugs.debian.org/708586 * Improve the test suite. -- Jakub Wilk Fri, 17 May 2013 15:23:30 +0200 i18nspector (0.9) unstable; urgency=low * Summary of tag changes: + Added: - inconsistent-leading-newlines - inconsistent-trailing-newlines * Check for inconsistent leading/trailing newlines in messages. * Check for unusual characters also in plural translations. * Add information about version and date to the manual page. * Fix stripping delay annotations from terminfo capabilities. -- Jakub Wilk Wed, 15 May 2013 19:37:44 +0200 i18nspector (0.8.3) unstable; urgency=low * Improve the test suite. + Skip some tests when run with (pseudo-)root privileges. Thanks to Stuart Prescott for the bug report. * Add “test” target to Makefile. Thanks to Kyrill Detinov for the bug report. * Recognize “PROJECT VERSION” as boilerplate in the Project-Id-Version header field. -- Jakub Wilk Fri, 03 May 2013 01:23:29 +0200 i18nspector (0.8.2) unstable; urgency=low * Make it possible to declare that a language has more than one correct Plural-Forms. Thanks to Guillem Jover for the bug report. * Add plural forms information for the following languages: Belarusian, Bosnian, Croatian, Hungarian, Russian, Serbian, Turkish, Ukrainian. * Improve the test suite. -- Jakub Wilk Thu, 11 Apr 2013 01:13:24 +0200 i18nspector (0.8.1) unstable; urgency=low * Improve the documentation. + Document the dependencies. Thanks to Kyrill Detinov for the bug report. + Fix a grammar mistake in the unknown-encoding description. + Update description in the “NAME” section of the manual page. + Rename the “USAGE” section of the manual page as “SYNOPSIS”. + Add “DESCRIPTION” section to the manual page. + Document that --debian is enabled on modern Debian(-like) systems. * Remove an incorrect assertion in the plural expression parser. Thanks to Fabio Pirola for the bug report. * Improve the test suite. -- Jakub Wilk Sun, 24 Feb 2013 12:24:46 +0100 i18nspector (0.8) unstable; urgency=low * Summary of tag changes: + Added: - incorrect-plural-forms - incorrect-unused-plural-forms * Add writing system information for the following languages: Burmese, Maori. * Comment out plural forms information for Hungarian and some Slavic languages: Belarusian, Bosnian, Croatian, Russian, Slovak, Serbian and Ukrainian; there is no consensus for the correct plural forms expression for them. * Check for mismatches between Plural-Forms declarations and i18nspector's linguistic data. -- Jakub Wilk Fri, 01 Feb 2013 01:32:42 +0100 i18nspector (0.7.3) unstable; urgency=low * Avoid very long lists of unrepresentable characters; output at most 5 characters at a time. * Output at most 5 items of long integer ranges. * Add writing system information for the following languages: Chinese, English with Shavian alphabet, Japanese, Korean, Malagasy, Pashto, Tagalog, Volapük. * Add plural forms information for the following languages: Frisian, Malagasy, Pashto, Tagalog, Xhosa. * Improve the test suite. -- Jakub Wilk Fri, 25 Jan 2013 01:32:28 +0100 i18nspector (0.7.2) unstable; urgency=low * Add writing system information for the following languages: Assamese, Bengali, Breton, Dzongkha, Esperanto, Galician, Gujarati, Hindi, Kannada, Khmer, Malayalam, Marathi, Nepali, Oriya, Punjabi, Sindhi, Serbian Ijekavian with Latin alphabet, Sinhala, Tajik, Tamil, Telugu, Thai, Urdu, Vietnamese, Walloon. * Update alphabet information for the following languages: Asturian, Spanish. * Add plural forms information for the following languages: Afrikaans: Albanian, Amharic, Assamese, Asturian, Basque, Bengali, Breton, Catalan, Galician, Georgian, Gujarati, Hindi, Indonesian, Interlingua, Kazakh, Khmer, Kinyarwanda, Kurdish Low German, Maithili, Malayalam, Marathi, Mongolian, Nepali, Occitan, Oriya, Persian, Punjabi, Sinhala, Tajik, Tamil, Telugu, Urdu, Uyghur. -- Jakub Wilk Fri, 18 Jan 2013 00:20:50 +0100 i18nspector (0.7.1) unstable; urgency=low * Add writing system information for: - Mongolian; - Semitic languages: Amharic, Arabic, Geez, Hebrew, Tigre, Tigrinya; - Turkic languages: Azerbaijani, Crimean Tatar, Kazakh, Kyrgyz, Tatar, Turkish, Tuvinian, Uyghur, Uzbek; - Uralic languages: Estonian, Finnish, Hungarian, Northern Sami. -- Jakub Wilk Fri, 11 Jan 2013 14:05:44 +0100 i18nspector (0.7) unstable; urgency=low * Summary of tag changes: + Added: - empty-file - invalid-language-team * Check for empty files. * Check for use of RFC 2606 reserved domain names. * Add alphabet information for: - Iranian languages: Kurdish, Ossetic, Persian; - Georgian; - Basque; - Northwest Caucasian languages: Abkhazian, Adyghe. * Handle some malformed MO files more gracefully. * Add a prefix to temporary directory names. * Make it possible to override code/data directory with an environment variable (I18NSPECTOR_BASEDIR). * Produce a useful error message when one tries to run the script with Python < 3.2. * Improve the test suite. -- Jakub Wilk Fri, 04 Jan 2013 18:12:30 +0100 i18nspector (0.6) unstable; urgency=low * Summary of tag changes: + Added: - arithmetic-error-in-plural-forms - arithmetic-error-in-unused-plural-forms - codomain-error-in-plural-forms - codomain-error-in-unused-plural-forms * Perform more checks on Plural-Forms. * Rename the ‘po-header-fields’ data file to ‘header-fields’. * User terminfo for color terminal support, instead of hardcoded EMCA-48 sequences. * Improve the test suite. * Remove some dead code. * Use ast.literal_eval() instead of eval(). -- Jakub Wilk Sun, 16 Dec 2012 21:16:28 +0100 i18nspector (0.5) unstable; urgency=low * Summary of tag changes: + Added: - stray-header-line * If a typo or a capitalization error in a header field name is detected, suggest the correct name. * Check for header lines that do not belong to any header fields. * Refactor the environment patching code. * Optimize PO file decoding. * Improve the test suite. -- Jakub Wilk Fri, 07 Dec 2012 23:08:27 +0100 i18nspector (0.4.1) unstable; urgency=low * Rename the package. -- Jakub Wilk Sun, 02 Dec 2012 16:54:08 +0100 gettext-inspector (0.4) unstable; urgency=low * Summary of tag changes: + Added: - inconsistent-number-of-plural-forms - incorrect-number-of-plural-forms - no-plural-forms-header-field - no-required-plural-forms-header-field - syntax-error-in-unused-plural-forms * Don't unpack control file directories of Debian binary packages; they almost certainly don't contain any interesting files. * Add DEL (U+007F) to the list of control characters. * Change the way message identifiers are formatted in tag output. * Perform more checks on Plural-Forms. * Upgrade syntax-error-in-plural-forms severity to serious. * Don't crash when parsing dates with double space between date and time. * Don't allow whitespace characters other than space and tab in plural expressions. * Don't emit spurious duplicate-header-field tags on multi-line header fields. * Don't complain about issues with obsolete messages. * Don't guess language from PO file name if it appears to contain an encoding declaration, as it's very likely that something else has been confused for the apparent encoding. * Try to propose encoding for invalid-content-type. * Fix untrusted input sanitization. * Work around an escape sequence decoding bug in polib. https://bitbucket.org/izi/polib/issues/31 * Fix typos and formatting errors in the manual page. * Improve the test suite. -- Jakub Wilk Fri, 30 Nov 2012 00:08:29 +0100 gettext-inspector (0.3) unstable; urgency=low * Summary of tag changes: + Added: - duplicate-header-field - duplicate-message-definition - non-ascii-compatible-encoding + Renamed: - unusual-character-in-translation (from c1-control-characters) * Add alphabet information for: - Dutch; - Romance languages (Asturian, Catalan, Corsican, French, Italian, Occitan, Portuguese, Romanian, Spanish). * Add national varieties of English and Chinese languages to the language data file. * Add “Brazilian Portuguese” as another name for pt_BR. * Check for duplicate message definitions. * Check for duplicate header fields. * Check for encodings incompatible with ASCII. * Check for more unusual characters in translations: - C0 control characters; - replacement character (U+FFFD); - inverted question mark (U+00BF) directly after a letter. * Work around a newline decoding bug in polib. https://bugs.debian.org/692283 * Improve the test suite. -- Jakub Wilk Thu, 22 Nov 2012 23:50:05 +0100 gettext-inspector (0.2) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-language-team - boilerplate-in-last-translator - invalid-last-translator - language-team-equal-to-last-translator - no-language-team-header-field - no-last-translator-header-field * Add support for the following encodings: - EUC-TW - GEORGIAN-PS - KOI8-RU - KOI8-T - VISCII * Don't fail if /etc/os-release doesn't exist. * Improve the test suite. * Add alphabet information for: - Albanian; - Armenian; - Baltic languages (Latvian, Lithuanian); - Celtic languages (Irish, Scottish Gaelic, Welsh); - Greek; - Germanic languages (Danish, Faroese, Frisian, German, Icelandic, Low German, Norwegian, Swedish); - South Slavic languages (Bosnian, Bulgarian, Croatian, Macedonian, Slovenian, Serbian). * Validate the Last-Translator and Language-Team header fields. -- Jakub Wilk Fri, 16 Nov 2012 19:57:26 +0100 gettext-inspector (0.1.1) unstable; urgency=low * Improve the test suite. * Makefile: remove bogus shebang. Thanks to Paul Wise for the bug report. * Add “This file has been generated automatically by […]. Do not edit.” comments where appropriate. * Add alphabet information for East Slavic languages (Belarusian, Russian, Ukrainian). * Do not make KOI8-RU an alias for KOI8-R. They are in fact distinct encodings. -- Jakub Wilk Mon, 12 Nov 2012 16:10:21 +0100 gettext-inspector (0.1) unstable; urgency=low * Initial release. * Summary of tag changes: + Added: - ancient-date - boilerplate-in-project-id-version - boilerplate-in-report-msgid-bugs-to - broken-encoding - c1-control-characters - date-from-future - encoding-in-language-header-field - invalid-content-transfer-encoding - invalid-content-type - invalid-date - invalid-language - invalid-mime-version - invalid-mo-file - invalid-report-msgid-bugs-to - language-disparity - language-variant-does-not-affect-translation - no-content-transfer-encoding-header-field - no-content-type-header-field - no-date-header-field - no-language-header-field - no-mime-version-header-field - no-package-name-in-project-id-version - no-project-id-version-header-field - no-report-msgid-bugs-to-header-field - no-version-in-project-id-version - non-portable-encoding - os-error - syntax-error-in-plural-forms - syntax-error-in-po-file - unable-to-determine-language - unknown-encoding - unknown-file-type - unknown-header-field - unknown-poedit-language - unrepresentable-characters -- Jakub Wilk Sun, 11 Nov 2012 16:22:46 +0100 i18nspector-0.27.1/doc/i18nspector.10000644000000000000000000015141314275257160017002 0ustar00rootroot00000000000000.\" Man page generated from reStructuredText. . .TH I18NSPECTOR 1 "2022-08-11" "i18nspector 0.27.1" "" .SH NAME i18nspector \- checking tool for gettext POT, PO and MO files . .nr rst2man-indent-level 0 . .de rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBi18nspector\fP [\fIoptions\fP] \fIfile\fP [\fIfile\fP …] .SH DESCRIPTION .sp \fBi18nspector\fP is a tool for checking translation templates (POT), message catalogues (PO) and compiled message catalogues (MO) files for common problems. These files are used by the GNU gettext translation functions and tools in many different development environments. .SH OPTIONS .INDENT 0.0 .TP .BI \-l \ lang\fR,\fB \ \-\-language \ lang Assume this language. \fIlang\fP should be a 2\- or 3\-letter ISO 639 language code, possibly followed by underscore and a 2\-letter ISO 3166 territory code. .TP .B \-\-unpack\-deb Allow unpacking Debian (binary or source) packages. .TP .BI \-j \ n\fR,\fB \ \-\-jobs \ n Use \fIn\fP processes in parallel. \fIn\fP can be a positive integer, or \fBauto\fP to determine the number automatically. The default is to use only a single process. .TP .B \-h\fP,\fB \-\-help Show help message and exit. .TP .B \-\-version Show version information and exit. .UNINDENT .SH OUTPUT FORMAT .sp The following format is used for all the reported problems: .sp \ \ \fIcode\fP\fB:\fP \fIfile\fP\fB:\fP \fItag\fP [\fIextra\fP] .sp where: .INDENT 0.0 .IP \(bu 2 \fIcode\fP is a letter indicating type of the message: \fBE\fP (error), \fBW\fP (warning), \fBI\fP (informative message), or \fBP\fP (pedantic message); .IP \(bu 2 \fItag\fP is a name of the problem that was discovered; .IP \(bu 2 \fIextra\fP can contain additional information about the problem. .UNINDENT .SH TAGS .\" This file has been generated automatically by private/tags-as-rst. .\" Do not edit. . .SS ancient\-date .sp The date refers to the time before the first GNU gettext release. As such, it's extremely unlikely to be correct. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://git.savannah.gnu.org/cgit/gettext.git/tree/ChangeLog.0#n1767\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS arithmetic\-error\-in\-plural\-forms .sp Computing a plural form value triggers division by zero or integer overflow. This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS arithmetic\-error\-in\-unused\-plural\-forms .sp Computing a plural form value triggers division by zero or integer overflow. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS boilerplate\-in\-content\-type .sp The Content\-Type header field contains xgettext boilerplate. It should be in the form \fBtext/plain; charset=\fP\fIencoding\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-date .sp The date header field contains xgettext boilerplate. The date format should be \fBYYYY\-MM\-DD hh:mm+ZZzz\fP, e.g. \fB2011\-11\-05 10:14+0100\fP\&. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-initial\-comments .sp The initial comments contain xgettext or msginit boilerplate. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS boilerplate\-in\-language\-team .sp The Language\-Team header field contains xgettext boilerplate. It should contain English name of the language, and the email address or homepage URL of the language team. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-last\-translator .sp The Last\-Translator header field contains xgettext boilerplate. It should contain the last translator's name and email address. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-project\-id\-version .sp The Project\-Id\-Version header field contains xgettext boilerplate. It should contain the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-report\-msgid\-bugs\-to .sp The Report\-Msgid\-Bugs\-To header field contains xgettext boilerplate. It should contain an email address or URL where one can report bugs in the untranslated strings. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS broken\-encoding .sp Header fields and messages contained by this file couldn't be decoded to Unicode. The usual cause of this is incorrect or missing encoding declaration. .sp Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-5\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-argument\-type\-mismatch .sp There's a type mismatch between a C format argument in \fBmsgid\fP and the corresponding format argument in \fBmsgid_plural\fP; or between a C format argument in \fBmsgstr\fP and \fBmsgid\fP; or between a C format argument in \fBmsgstr[\fP\fIN\fP\fB]\fP and corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-error .sp A C format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-excess\-arguments .sp A C format string for \fBmsgid\fP consumes more arguments than \fBmsgid_plural\fP; or \fBmsgstr\fP consumes more arguments than \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP consumes more arguments than corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-missing\-arguments .sp A C format string for \fBmsgid\fP consumes fewer arguments than \fBmsgid_plural\fP; or \fBmsgstr\fP consumes fewer arguments than \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP consumes fewer arguments than corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB%d\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB%d\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-non\-portable\-conversion .sp A C format string uses a conversion specified or length modifier, for which a more portable replacement exists: .INDENT 0.0 .IP \(bu 2 For integer conversions (\fB%d\fP, \fB%i\fP, \fB%o\fP, \fB%u\fP, \fB%x\fP, and \fB%X\fP), use the \fBll\fP length modifier instead of \fBL\fP or \fBq\fP\&. .IP \(bu 2 For floating\-point conversions (\fB%a\fP, \fB%A\fP, \fB%e\fP, \fB%E\fP, \fB%f\fP, \fB%F\fP, \fB%g\fP, and \fB%G\fP), don't use the \fBl\fP length modifier. .IP \(bu 2 Use the \fBz\fP length modifier instead of \fBZ\fP\&. .IP \(bu 2 Use \fB%lc\fP instead of \fB%C\fP\&. .IP \(bu 2 Use \fB%ls\fP instead of \fB%S\fP\&. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS c\-format\-string\-redundant\-flag .sp A C format string includes a redundant character flag. Either it's a duplicate, or it has no effect: .INDENT 0.0 .IP \(bu 2 The \fB+\fP flag overrides the \fIspace\fP flag. .IP \(bu 2 The \fB\-\fP flag overrides the \fB0\fP flag. .IP \(bu 2 If a precision is given, the \fB0\fP flag has no effect on integer conversions (\fB%d\fP, \fB%i\fP, \fB%o\fP, \fB%u\fP, \fB%x\fP, and \fB%X\fP). .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS codomain\-error\-in\-plural\-forms .sp Either a plural form value is outside the declared range, or some values within the declared range can never be reached. This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS codomain\-error\-in\-unused\-plural\-forms .sp Either a plural form value is outside the declared range, or some values within the declared range can never be reached. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS conflict\-marker\-in\-header\-entry .sp The header contains a conflict marker (\fB#\-#\-#\-#\-#\fP \fI…\fP \fB#\-#\-#\-#\-#\fP). The conflict will have to be resolved manually. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Creating\-Compendia.html#Creating\-Compendia\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS conflict\-marker\-in\-translation .sp One of the translated messages appear to contain a conflict marker (\fB#\-#\-#\-#\-#\fP \fI…\fP \fB#\-#\-#\-#\-#\fP). The conflict will have to be resolved manually. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Creating\-Compendia.html#Creating\-Compendia\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS conflicting\-message\-flags .sp Two flags with conflicting meanings are associated with one of the messages. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS date\-from\-future .sp The date refers to the future. As such, it's extremely unlikely to be correct. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS distant\-header\-entry .sp The header entry in this file is preceded by other entries. The header entry should be always the first one. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS duplicate\-flag\-for\-header\-entry .sp Multiple identical flags are associated with the header entry. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS duplicate\-header\-entry .sp This file contains multiple header entries. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field .sp This file contains multiple header fields of the same name. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, wild\-guess .UNINDENT .UNINDENT .SS duplicate\-header\-field\-content\-transfer\-encoding .sp This file contains multiple Content\-Transfer\-Encoding header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-content\-type .sp This file contains multiple Content\-Type header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-date .sp This file contains multiple date header fields of the same name. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-language .sp This file contains multiple Language header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-language\-team .sp This file contains multiple Language\-Team header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-last\-translator .sp This file contains multiple Last\-Translator header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-mime\-version .sp This file contains multiple MIME\-Version header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-plural\-forms .sp This file contains multiple Plural\-Forms header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-project\-id\-version .sp This file contains multiple Project\-Id\-Version header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-report\-msgid\-bugs\-to .sp This file contains multiple Report\-Msgid\-Bugs\-To header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-x\-poedit .sp This file contains multiple X\-Poedit\-\fI*\fP header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-message\-definition .sp This file contains multiple definitions of the same message. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-message\-flag .sp Multiple identical flags are associated with one of the messages. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS empty\-file .sp This file doesn't contain any messages. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS empty\-msgid\-message\-with\-plural\-forms .sp The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call \fBngettext("", …)\fP\&. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS empty\-msgid\-message\-with\-source\-code\-references .sp The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call \fBgettext("")\fP\&. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS encoding\-in\-language\-header\-field .sp The language header field contains encoding declaration. Such information shouldn't be included in this field. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS fuzzy\-header\-entry .sp The header entry is marked as fuzzy. For compatibility with very old (<< 0.11) \fBmsgfmt\fP(1) versions, which didn't support fuzzy header entries, it shouldn't be marked as such. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://git.savannah.gnu.org/cgit/gettext.git/tree/NEWS?id=v0.11#n44\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS inconsistent\-leading\-newlines .sp Some strings in an entry start with a newline, but some don't. Either all of them should start with a newline, or none of them should. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS inconsistent\-number\-of\-plural\-forms .sp Number of plural forms in a message definition doesn't match number of plural forms declared in another message definition. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS inconsistent\-trailing\-newlines .sp Some strings in an entry end with a newline, but some don't. Either all of them should end with a newline, or none of them should. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS incorrect\-number\-of\-plural\-forms .sp Number of plural forms in a message definition doesn't match number of plural forms declared in the header. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS invalid\-content\-transfer\-encoding .sp Value of the Content\-Transfer\-Encoding header field is invalid. It should be \fB8bit\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-6.1\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS invalid\-content\-type .sp Value of the Content\-Type header field should is invalid. It should be in the form \fBtext/plain; charset=\fP\fIencoding\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-5\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS invalid\-date .sp The date is invalid or in an invalid format. The format should be \fBYYYY\-MM\-DD hh:mm+ZZzz\fP, e.g. \fB2011\-11\-05 10:14+0100\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS invalid\-language .sp The Language header field couldn't be parsed, or it contains an unknown language. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS invalid\-language\-team .sp The Language\-Team header field contains an e\-mail address that uses a reserved domain name, or a partially qualified domain name. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://tools.ietf.org/html/rfc2606\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS invalid\-last\-translator .sp The Last\-Translator header field could neither be parsed as an e\-mail, or the e\-mail address uses a reserved domain name, or a partially qualified domain name. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2606\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS invalid\-mime\-version .sp Value of the MIME\-Version header field is invalid. It should be \fB1.0\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://tools.ietf.org/html/rfc2045#section\-4\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS invalid\-mo\-file .sp This file couldn't be parsed a MO file. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS invalid\-range\-flag .sp A \fBrange:\fP flag couldn't be parsed, or the designated range contained fewer than two numbers. The syntax is \fBrange:\fP \fImin\fP\fB\&..\fP\fImax\fP, where both values are non\-negative integers. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS invalid\-report\-msgid\-bugs\-to .sp The Report\-Msgid\-Bugs\-To header field could neither be parsed as an e\-mail nor as a URL, or the e\-mail address uses a reserved domain name, or a partially qualified domain name. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2606\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS language\-disparity .sp Language of this file has been declared in multiple places, but the declarations don't match. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS language\-team\-equal\-to\-last\-translator .sp Language\-Team and Last\-Translator header fields contain the same e\-mail address. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS language\-variant\-does\-not\-affect\-translation .sp The Language header field contains a variant designator that is not relevant for the message translation. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS leading\-junk\-in\-plural\-forms .sp The Plural\-Forms header field contains unexpected text before the \fBnplurals=\fP string. .sp GNU gettext runtime ignores such leading junk, but other header parsers might be less liberal in what they accept. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS malformed\-xml .sp The original string or the translated string contains an XML fragment, which is not well\-formed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.w3.org/TR/REC\-xml/#sec\-well\-formed\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS no\-content\-transfer\-encoding\-header\-field .sp The Content\-Transfer\-Encoding header field doesn't exist. It should be set to \fB8bit\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-6.1\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-content\-type\-header\-field .sp The Content\-Type header field doesn't exist. It should be set to \fBtext/plain; charset=\fP\fIencoding\fP\&. .sp Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-5\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS no\-date\-header\-field .sp The date header field doesn't exist. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS no\-language\-header\-field .sp The Language header field doesn't exist. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-language\-team\-header\-field .sp The Language\-Team header field does not exist. It should contain English name of the language, and the email address or homepage URL of the language team. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-last\-translator\-header\-field .sp The Last\-Translator header field doesn't exist. It should contain the last translator's name and email address. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS no\-mime\-version\-header\-field .sp The MIME\-Version header field doesn't exist. It should be to set to \fB1.0\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://tools.ietf.org/html/rfc2045#section\-4\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-package\-name\-in\-project\-id\-version .sp The Project\-Id\-Version header field doesn't appear to contain any name. It should contain both the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS no\-plural\-forms\-header\-field .sp The Plural\-Forms header field does not exist, even though some of the messages use plural forms (although none of them have been translated). .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS no\-project\-id\-version\-header\-field .sp The Project\-Id\-Version header field does not exist. It should contain the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS no\-report\-msgid\-bugs\-to\-header\-field .sp The Report\-Msgid\-Bugs\-To header field does not exist or it is empty. It should contain an email address or URL where one can report bugs in the untranslated strings. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS no\-required\-plural\-forms\-header\-field .sp The Plural\-Forms header field does not exist, even though some of the translated messages use plural forms. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS no\-version\-in\-project\-id\-version .sp The Project\-Id\-Version header field doesn't appear to contain any version. It should contain both the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS non\-ascii\-compatible\-encoding .sp This file uses an encoding that is not compatible with ASCII. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS non\-portable\-encoding .sp This file uses an encoding that is not widely supported by software. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-list\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS os\-error .sp An input/output error or another operating system error occurred while checking this file. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS partially\-translated\-message .sp Translation is missing for some plural forms of a message. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS perl\-brace\-format\-string\-error .sp A Perl format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS perl\-brace\-format\-string\-missing\-argument .sp A Perl format string for \fBmsgid\fP doesn't use a named argument that is used in \fBmsgid_plural\fP; or \fBmsgstr\fP doesn't use a named argument that is used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP doesn't use a named argument that is used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB{n}\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB{n}\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS perl\-brace\-format\-string\-unknown\-argument .sp A Perl format string for \fBmsgid\fP uses a named argument that isn't used in \fBmsgid_plural\fP; or \fBmsgstr\fP uses a named argument that isn't used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP uses a named argument that isn't used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. This indicates that the conversion would try to consume an argument that weren't supplied. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-argument\-type\-mismatch .sp There's a type mismatch between a Python format argument in \fBmsgid\fP and the corresponding format argument in \fBmsgid_plural\fP; or between a Python format argument in \fBmsgstr\fP and \fBmsgid\fP; or between a Python format argument in \fBmsgstr[\fP\fIN\fP\fB]\fP and \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-error .sp A Python format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-missing\-argument .sp A Python format string for \fBmsgid\fP doesn't use a named argument that is used in \fBmsgid_plural\fP; or \fBmsgstr\fP doesn't use a named argument that is used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP doesn't use a named argument that is used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB{n}\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB{n}\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-unknown\-argument .sp A Python format string for \fBmsgid\fP uses a named argument that isn't used in \fBmsgid_plural\fP; or \fBmsgstr\fP uses a named argument that isn't used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP uses a named argument that isn't used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. This indicates that the conversion would try to consume an argument that weren't supplied. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-argument\-number\-mismatch .sp A Python format string for \fBmsgid\fP consumes more arguments than \fBmsgid_plural\fP; or \fBmsgstr\fP consumes more arguments than \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP consumes more arguments than \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Python, unlike C, requires that all unnamed arguments must be consumed during conversion. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-argument\-type\-mismatch .sp There's a type mismatch between a Python format argument in \fBmsgid\fP and the corresponding format argument in \fBmsgid_plural\fP; or between a Python format argument in \fBmsgstr\fP and \fBmsgid\fP; or between a Python format argument in \fBmsgstr[\fP\fIN\fP\fB]\fP and \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-error .sp A Python format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-missing\-argument .sp A Python format string for \fBmsgid\fP doesn't use a named argument that is used in \fBmsgid_plural\fP; or \fBmsgstr\fP doesn't use a named argument that is used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP doesn't use a named argument that is used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB%d\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB%d\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-multiple\-unnamed\-arguments .sp A Python format string uses multiple unnamed arguments (such as \fB%d\fP). The translator might need to reorder the arguments to properly translate the message, but this is not possible with unnamed arguments. Named arguments (such as \fB%(num)d\fP) should be used instead. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-obsolete\-conversion .sp A Python format string uses an obsolete conversion specifier: .INDENT 0.0 .IP \(bu 2 Use \fB%d\fP instead of \fB%u\fP\&. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-redundant\-flag .sp A Python format string includes a redundant character flag. Either it's a duplicate, or it has no effect: .INDENT 0.0 .IP \(bu 2 The \fB+\fP flag overrides the \fIspace\fP flag. .IP \(bu 2 The \fB\-\fP flag overrides the \fB0\fP flag. .IP \(bu 2 If a precision is given, the \fB0\fP flag has no effect on integer conversions (\fB%d\fP, \fB%i\fP, \fB%o\fP, \fB%u\fP, \fB%x\fP, and \fB%X\fP). .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-redundant\-length .sp A Python format string includes a redundant length modifier. Length modifiers (\fBh\fP, \fBl\fP, or \fBL\fP) have no effect in Python. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-redundant\-precision .sp A C format string includes precision that has no effect on the conversion. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-unknown\-argument .sp A Python format string for \fBmsgid\fP uses a named argument that isn't used in \fBmsgid_plural\fP; or \fBmsgstr\fP uses a named argument that isn't used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP uses a named argument that isn't used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. This indicates that the conversion would try to consume an argument that weren't supplied. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-unnamed\-plural\-argument .sp A Python format string uses an unnamed arguments (such as \fB%d\fP) in the context of plural forms. The translator might want not to use the numeric argument in the singular form; but this is not possible if the argument is unnamed, because Python, unlike C, requires that all unnamed arguments must be consumed during conversion. Named arguments (such as \fB%(n)d\fP) should be used instead. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 wishlist, possible .UNINDENT .UNINDENT .SS qt\-plural\-format\-mistaken\-for\-c\-format .sp A \fBc\-format\fP flag is associated with the message, but \fBqt\-plural\-format\fP should be used instead. .sp The only C format directive that the message uses is \fB%n\fP\&. It is very atypical to use it alone in a C format string. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://doc.qt.io/qt\-5/i18n\-source\-translation.html#handling\-plurals\fP \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS range\-flag\-without\-plural\-string .sp A \fBrange:\fP flag is associated with a message that doesn't have plural string. \fBrange:\fP flags only make sense for translations involving plural forms. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS redundant\-message\-flag .sp A flag associated with one of the messages is redundant, because it's implied by another flag. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS stray\-header\-line .sp The header contains a line that does not belong to any header field. Note that RFC\-822\-style folding of long headers is not supported. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://lists.gnu.org/archive/html/bug\-gettext/2012\-12/msg00010.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS stray\-previous\-msgid .sp The message entry contains annotations about previous untranslated string (\fB#| msgid\fP\ \fI\&...\fP), even though the message is not marked as fuzzy. These annotations are only useful for fuzzy messages, and should be removed when unfuzzying. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS syntax\-error\-in\-plural\-forms .sp Value of the Plural\-Forms header field could not be parsed. It should be in the form \fBnplurals=\fP\fIn\fP\fB; plural=\fP\fIexpression\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS syntax\-error\-in\-po\-file .sp This file couldn't be parsed a PO file. In some rare cases this is due to incorrect or missing encoding declaration. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP \fI\%https://bugs.debian.org/692283\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS syntax\-error\-in\-unused\-plural\-forms .sp Value of the Plural\-Forms header field could not be parsed. (But there are no translated messages which use plural forms.) It should be in the form \fBnplurals=\fP\fIn\fP\fB; plural=\fP\fIexpression\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS trailing\-junk\-in\-plural\-forms .sp The Plural\-Forms header field contains unexpected text after the plural expression. .sp GNU gettext runtime ignores such trailing junk, but other header parsers might be less liberal in what they accept. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS translation\-in\-template .sp The PO template file contains a translated message. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS unable\-to\-determine\-language .sp i18nspector was unable to determine language of this file. Absence of this information will prevent it from performing further checks. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, wild\-guess .UNINDENT .UNINDENT .SS unexpected\-flag\-for\-header\-entry .sp An unexpected flag is associated with the header entry. The only flag that makes sense for the header entry is \fBfuzzy\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS unknown\-encoding .sp This file declares an encoding that couldn't be recognized by i18nspector. It might be a typo. Absence of encoding information will prevent i18nspector from performing further checks. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS unknown\-file\-type .sp File format of this file couldn't be recognized. It might be a bug in i18nspector. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, wild\-guess .UNINDENT .UNINDENT .SS unknown\-header\-field .sp The header field name is unknown to i18nspector. It might be a typo or a capitalization error (header field names are case\-sensitive). .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://lists.gnu.org/archive/html/bug\-gettext/2012\-12/msg00010.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, wild\-guess .UNINDENT .UNINDENT .SS unknown\-message\-flag .sp An unknown flag is associated with one of the messages. It might be a typo. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, wild\-guess .UNINDENT .UNINDENT .SS unknown\-poedit\-language .sp Language declared in X\-Poedit\-Language couldn't be recognized. It might be a bug in i18nspector. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, wild\-guess .UNINDENT .UNINDENT .SS unrepresentable\-characters .sp The declared encoding cannot represent all characters commonly used in this language. This is a strong indication that the declared encoding is incorrect. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS unusual\-character\-in\-header\-entry .sp The header entry contains an unusual character. This is usually an indication of an encoding problem, such as: .INDENT 0.0 .IP \(bu 2 using ISO 2022 escape sequences, or .IP \(bu 2 using UTF\-8 despite declaring an 8\-bit encoding. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.unicode.org/faq/utf_bom.html#bom6\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS unusual\-character\-in\-translation .sp One of the translated messages contains an unusual character. This is usually an indication of an encoding problem, such as: .INDENT 0.0 .IP \(bu 2 using ISO 2022 escape sequences, or .IP \(bu 2 using UTF\-8 despite declaring an 8\-bit encoding. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.unicode.org/faq/utf_bom.html#bom6\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS unusual\-plural\-forms .sp The Plural\-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS unusual\-unused\-plural\-forms .sp The Plural\-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. (But there are no translated messages which use plural forms.) .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SH SEE ALSO .sp \fBmsgfmt\fP(1), particularly the \fB\-c\fP option . .\" Generated by docutils manpage writer. . i18nspector-0.27.1/doc/manpage.rst0000644000000000000000000000326614275257143016706 0ustar00rootroot00000000000000=========== i18nspector =========== ---------------------------------------------- checking tool for gettext POT, PO and MO files ---------------------------------------------- :manual section: 1 :version: i18nspector 0.27.1 :date: |date| Synopsis -------- **i18nspector** [*options*] *file* [*file* …] Description ----------- **i18nspector** is a tool for checking translation templates (POT), message catalogues (PO) and compiled message catalogues (MO) files for common problems. These files are used by the GNU gettext translation functions and tools in many different development environments. Options ------- -l lang, --language lang Assume this language. *lang* should be a 2- or 3-letter ISO 639 language code, possibly followed by underscore and a 2-letter ISO 3166 territory code. --unpack-deb Allow unpacking Debian (binary or source) packages. -j n, --jobs n Use *n* processes in parallel. *n* can be a positive integer, or ``auto`` to determine the number automatically. The default is to use only a single process. -h, --help Show help message and exit. --version Show version information and exit. Output format ------------- The following format is used for all the reported problems:   *code*\ **:** *file*\ **:** *tag* [*extra*] where: * *code* is a letter indicating type of the message: **E** (error), **W** (warning), **I** (informative message), or **P** (pedantic message); * *tag* is a name of the problem that was discovered; * *extra* can contain additional information about the problem. Tags ---- .. include:: tags.rst .. |date| date:: %Y-%m-%d See also -------- **msgfmt**\ (1), particularly the ``-c`` option .. vim:ts=3 sts=3 sw=3 i18nspector-0.27.1/doc/tags.rst0000644000000000000000000012174514275257157016244 0ustar00rootroot00000000000000.. This file has been generated automatically by private/tags-as-rst. Do not edit. ancient-date ~~~~~~~~~~~~ The date refers to the time before the first GNU gettext release. As such, it's extremely unlikely to be correct. References: | https://git.savannah.gnu.org/cgit/gettext.git/tree/ChangeLog.0#n1767 Severity, certainty: normal, certain arithmetic-error-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Computing a plural form value triggers division by zero or integer overflow. This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible arithmetic-error-in-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Computing a plural form value triggers division by zero or integer overflow. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: normal, possible boilerplate-in-content-type ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Content-Type header field contains xgettext boilerplate. It should be in the form ``text/plain; charset=``\ *encoding*. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files Severity, certainty: important, certain boilerplate-in-date ~~~~~~~~~~~~~~~~~~~ The date header field contains xgettext boilerplate. The date format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. Severity, certainty: normal, certain boilerplate-in-initial-comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The initial comments contain xgettext or msginit boilerplate. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, possible boilerplate-in-language-team ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Language-Team header field contains xgettext boilerplate. It should contain English name of the language, and the email address or homepage URL of the language team. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain boilerplate-in-last-translator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Last-Translator header field contains xgettext boilerplate. It should contain the last translator's name and email address. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain boilerplate-in-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field contains xgettext boilerplate. It should contain the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain boilerplate-in-report-msgid-bugs-to ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Report-Msgid-Bugs-To header field contains xgettext boilerplate. It should contain an email address or URL where one can report bugs in the untranslated strings. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain broken-encoding ~~~~~~~~~~~~~~~ Header fields and messages contained by this file couldn't be decoded to Unicode. The usual cause of this is incorrect or missing encoding declaration. Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files | https://tools.ietf.org/html/rfc2045#section-5 Severity, certainty: serious, possible c-format-string-argument-type-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There's a type mismatch between a C format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a C format argument in ``msgstr`` and ``msgid``; or between a C format argument in ``msgstr[``\ *N*\ ``]`` and corresponding ``msgid`` or ``msgid_plural``. References: | **printf**\ (3) | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible c-format-string-error ~~~~~~~~~~~~~~~~~~~~~ A C format string could not be parsed. References: | **printf**\ (3) Severity, certainty: serious, possible c-format-string-excess-arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than corresponding ``msgid`` or ``msgid_plural``. References: | **printf**\ (3) | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible c-format-string-missing-arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string for ``msgid`` consumes fewer arguments than ``msgid_plural``; or ``msgstr`` consumes fewer arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes fewer arguments than corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" msgstr[3] "jedan bajt" References: | **printf**\ (3) | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible c-format-string-non-portable-conversion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string uses a conversion specified or length modifier, for which a more portable replacement exists: * For integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``), use the ``ll`` length modifier instead of ``L`` or ``q``. * For floating-point conversions (``%a``, ``%A``, ``%e``, ``%E``, ``%f``, ``%F``, ``%g``, and ``%G``), don't use the ``l`` length modifier. * Use the ``z`` length modifier instead of ``Z``. * Use ``%lc`` instead of ``%C``. * Use ``%ls`` instead of ``%S``. References: | **printf**\ (3) Severity, certainty: pedantic, possible c-format-string-redundant-flag ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string includes a redundant character flag. Either it's a duplicate, or it has no effect: * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). References: | **printf**\ (3) Severity, certainty: pedantic, possible codomain-error-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Either a plural form value is outside the declared range, or some values within the declared range can never be reached. This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, certain codomain-error-in-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Either a plural form value is outside the declared range, or some values within the declared range can never be reached. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: normal, certain conflict-marker-in-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The header contains a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. References: | https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia Severity, certainty: serious, certain conflict-marker-in-translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One of the translated messages appear to contain a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. References: | https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia Severity, certainty: serious, possible conflicting-message-flags ~~~~~~~~~~~~~~~~~~~~~~~~~ Two flags with conflicting meanings are associated with one of the messages. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: important, possible date-from-future ~~~~~~~~~~~~~~~~ The date refers to the future. As such, it's extremely unlikely to be correct. Severity, certainty: normal, certain distant-header-entry ~~~~~~~~~~~~~~~~~~~~ The header entry in this file is preceded by other entries. The header entry should be always the first one. Severity, certainty: important, certain duplicate-flag-for-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Multiple identical flags are associated with the header entry. Severity, certainty: minor, certain duplicate-header-entry ~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple header entries. Severity, certainty: serious, certain duplicate-header-field ~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple header fields of the same name. Severity, certainty: minor, wild-guess duplicate-header-field-content-transfer-encoding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Content-Transfer-Encoding header fields. Severity, certainty: pedantic, certain duplicate-header-field-content-type ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Content-Type header fields. Severity, certainty: serious, certain duplicate-header-field-date ~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple date header fields of the same name. Severity, certainty: normal, certain duplicate-header-field-language ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Language header fields. Severity, certainty: important, certain duplicate-header-field-language-team ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Language-Team header fields. Severity, certainty: normal, certain duplicate-header-field-last-translator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Last-Translator header fields. Severity, certainty: normal, certain duplicate-header-field-mime-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple MIME-Version header fields. Severity, certainty: pedantic, certain duplicate-header-field-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Plural-Forms header fields. Severity, certainty: serious, certain duplicate-header-field-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Project-Id-Version header fields. Severity, certainty: minor, certain duplicate-header-field-report-msgid-bugs-to ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Report-Msgid-Bugs-To header fields. Severity, certainty: normal, certain duplicate-header-field-x-poedit ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple X-Poedit-*\** header fields. Severity, certainty: normal, certain duplicate-message-definition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple definitions of the same message. Severity, certainty: serious, certain duplicate-message-flag ~~~~~~~~~~~~~~~~~~~~~~ Multiple identical flags are associated with one of the messages. Severity, certainty: minor, certain empty-file ~~~~~~~~~~ This file doesn't contain any messages. Severity, certainty: normal, certain empty-msgid-message-with-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``ngettext("", …)``. Severity, certainty: serious, certain empty-msgid-message-with-source-code-references ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``gettext("")``. Severity, certainty: serious, possible encoding-in-language-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The language header field contains encoding declaration. Such information shouldn't be included in this field. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain fuzzy-header-entry ~~~~~~~~~~~~~~~~~~ The header entry is marked as fuzzy. For compatibility with very old (<< 0.11) **msgfmt**\ (1) versions, which didn't support fuzzy header entries, it shouldn't be marked as such. References: | https://git.savannah.gnu.org/cgit/gettext.git/tree/NEWS?id=v0.11#n44 Severity, certainty: pedantic, certain inconsistent-leading-newlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some strings in an entry start with a newline, but some don't. Either all of them should start with a newline, or none of them should. Severity, certainty: important, possible inconsistent-number-of-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Number of plural forms in a message definition doesn't match number of plural forms declared in another message definition. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, certain inconsistent-trailing-newlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some strings in an entry end with a newline, but some don't. Either all of them should end with a newline, or none of them should. Severity, certainty: important, possible incorrect-number-of-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Number of plural forms in a message definition doesn't match number of plural forms declared in the header. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, certain invalid-content-transfer-encoding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Value of the Content-Transfer-Encoding header field is invalid. It should be ``8bit``. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2045#section-6.1 Severity, certainty: pedantic, certain invalid-content-type ~~~~~~~~~~~~~~~~~~~~ Value of the Content-Type header field should is invalid. It should be in the form ``text/plain; charset=``\ *encoding*. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files | https://tools.ietf.org/html/rfc2045#section-5 Severity, certainty: important, possible invalid-date ~~~~~~~~~~~~ The date is invalid or in an invalid format. The format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain invalid-language ~~~~~~~~~~~~~~~~ The Language header field couldn't be parsed, or it contains an unknown language. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: important, possible invalid-language-team ~~~~~~~~~~~~~~~~~~~~~ The Language-Team header field contains an e-mail address that uses a reserved domain name, or a partially qualified domain name. References: | https://tools.ietf.org/html/rfc2606 Severity, certainty: normal, possible invalid-last-translator ~~~~~~~~~~~~~~~~~~~~~~~ The Last-Translator header field could neither be parsed as an e-mail, or the e-mail address uses a reserved domain name, or a partially qualified domain name. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2606 Severity, certainty: normal, possible invalid-mime-version ~~~~~~~~~~~~~~~~~~~~ Value of the MIME-Version header field is invalid. It should be ``1.0``. References: | https://tools.ietf.org/html/rfc2045#section-4 Severity, certainty: pedantic, certain invalid-mo-file ~~~~~~~~~~~~~~~ This file couldn't be parsed a MO file. Severity, certainty: serious, certain invalid-range-flag ~~~~~~~~~~~~~~~~~~ A ``range:`` flag couldn't be parsed, or the designated range contained fewer than two numbers. The syntax is ``range:``\ *min*\ ``..``\ *max*, where both values are non-negative integers. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: important, certain invalid-report-msgid-bugs-to ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Report-Msgid-Bugs-To header field could neither be parsed as an e-mail nor as a URL, or the e-mail address uses a reserved domain name, or a partially qualified domain name. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2606 Severity, certainty: normal, possible language-disparity ~~~~~~~~~~~~~~~~~~ Language of this file has been declared in multiple places, but the declarations don't match. Severity, certainty: normal, possible language-team-equal-to-last-translator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Language-Team and Last-Translator header fields contain the same e-mail address. Severity, certainty: minor, possible language-variant-does-not-affect-translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Language header field contains a variant designator that is not relevant for the message translation. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, possible leading-junk-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field contains unexpected text before the ``nplurals=`` string. GNU gettext runtime ignores such leading junk, but other header parsers might be less liberal in what they accept. Severity, certainty: important, certain malformed-xml ~~~~~~~~~~~~~ The original string or the translated string contains an XML fragment, which is not well-formed. References: | https://www.w3.org/TR/REC-xml/#sec-well-formed Severity, certainty: serious, possible no-content-transfer-encoding-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Content-Transfer-Encoding header field doesn't exist. It should be set to ``8bit``. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2045#section-6.1 Severity, certainty: pedantic, certain no-content-type-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Content-Type header field doesn't exist. It should be set to ``text/plain; charset=``\ *encoding*. Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files | https://tools.ietf.org/html/rfc2045#section-5 Severity, certainty: important, certain no-date-header-field ~~~~~~~~~~~~~~~~~~~~ The date header field doesn't exist. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain no-language-header-field ~~~~~~~~~~~~~~~~~~~~~~~~ The Language header field doesn't exist. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: pedantic, certain no-language-team-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Language-Team header field does not exist. It should contain English name of the language, and the email address or homepage URL of the language team. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: pedantic, certain no-last-translator-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Last-Translator header field doesn't exist. It should contain the last translator's name and email address. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain no-mime-version-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The MIME-Version header field doesn't exist. It should be to set to ``1.0``. References: | https://tools.ietf.org/html/rfc2045#section-4 Severity, certainty: pedantic, certain no-package-name-in-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field doesn't appear to contain any name. It should contain both the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, possible no-plural-forms-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field does not exist, even though some of the messages use plural forms (although none of them have been translated). References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: minor, certain no-project-id-version-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field does not exist. It should contain the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain no-report-msgid-bugs-to-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Report-Msgid-Bugs-To header field does not exist or it is empty. It should contain an email address or URL where one can report bugs in the untranslated strings. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain no-required-plural-forms-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field does not exist, even though some of the translated messages use plural forms. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, certain no-version-in-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field doesn't appear to contain any version. It should contain both the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: pedantic, possible non-ascii-compatible-encoding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file uses an encoding that is not compatible with ASCII. Severity, certainty: serious, certain non-portable-encoding ~~~~~~~~~~~~~~~~~~~~~ This file uses an encoding that is not widely supported by software. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-list Severity, certainty: important, certain os-error ~~~~~~~~ An input/output error or another operating system error occurred while checking this file. Severity, certainty: serious, certain partially-translated-message ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Translation is missing for some plural forms of a message. Severity, certainty: serious, possible perl-brace-format-string-error ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Perl format string could not be parsed. References: | https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html Severity, certainty: serious, possible perl-brace-format-string-missing-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Perl format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" Here ``{n}`` should not be replaced with the spelled-out form ``jedan``. Either ``{n}`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" msgstr[3] "jedan bajt" References: | https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible perl-brace-format-string-unknown-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Perl format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. References: | https://www.gnu.org/software/gettext/manual/html_node/perl_002dformat.html | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible python-brace-format-string-argument-type-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. References: | https://docs.python.org/2/library/string.html#formatstrings Severity, certainty: serious, possible python-brace-format-string-error ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string could not be parsed. References: | https://docs.python.org/2/library/string.html#formatstrings Severity, certainty: serious, possible python-brace-format-string-missing-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" Here ``{n}`` should not be replaced with the spelled-out form ``jedan``. Either ``{n}`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" msgstr[3] "jedan bajt" References: | https://docs.python.org/2/library/string.html#formatstrings | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible python-brace-format-string-unknown-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. References: | https://docs.python.org/2/library/string.html#formatstrings | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible python-format-string-argument-number-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than ``msgid`` or ``msgid_plural``. Python, unlike C, requires that all unnamed arguments must be consumed during conversion. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python Severity, certainty: serious, possible python-format-string-argument-type-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: serious, possible python-format-string-error ~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string could not be parsed. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: serious, possible python-format-string-missing-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" msgstr[3] "jedan bajt" References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible python-format-string-multiple-unnamed-arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string uses multiple unnamed arguments (such as ``%d``). The translator might need to reorder the arguments to properly translate the message, but this is not possible with unnamed arguments. Named arguments (such as ``%(num)d``) should be used instead. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python Severity, certainty: serious, possible python-format-string-obsolete-conversion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string uses an obsolete conversion specifier: * Use ``%d`` instead of ``%u``. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-redundant-flag ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string includes a redundant character flag. Either it's a duplicate, or it has no effect: * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-redundant-length ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string includes a redundant length modifier. Length modifiers (``h``, ``l``, or ``L``) have no effect in Python. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-redundant-precision ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string includes precision that has no effect on the conversion. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-unknown-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible python-format-string-unnamed-plural-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string uses an unnamed arguments (such as ``%d``) in the context of plural forms. The translator might want not to use the numeric argument in the singular form; but this is not possible if the argument is unnamed, because Python, unlike C, requires that all unnamed arguments must be consumed during conversion. Named arguments (such as ``%(n)d``) should be used instead. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python Severity, certainty: wishlist, possible qt-plural-format-mistaken-for-c-format ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``c-format`` flag is associated with the message, but ``qt-plural-format`` should be used instead. The only C format directive that the message uses is ``%n``. It is very atypical to use it alone in a C format string. References: | https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals | **printf**\ (3) Severity, certainty: important, possible range-flag-without-plural-string ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``range:`` flag is associated with a message that doesn't have plural string. ``range:`` flags only make sense for translations involving plural forms. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: normal, certain redundant-message-flag ~~~~~~~~~~~~~~~~~~~~~~ A flag associated with one of the messages is redundant, because it's implied by another flag. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: pedantic, certain stray-header-line ~~~~~~~~~~~~~~~~~ The header contains a line that does not belong to any header field. Note that RFC-822-style folding of long headers is not supported. References: | https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html Severity, certainty: important, certain stray-previous-msgid ~~~~~~~~~~~~~~~~~~~~ The message entry contains annotations about previous untranslated string (``#| msgid``\ *...*), even though the message is not marked as fuzzy. These annotations are only useful for fuzzy messages, and should be removed when unfuzzying. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: minor, certain syntax-error-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Value of the Plural-Forms header field could not be parsed. It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, certain syntax-error-in-po-file ~~~~~~~~~~~~~~~~~~~~~~~ This file couldn't be parsed a PO file. In some rare cases this is due to incorrect or missing encoding declaration. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html | https://bugs.debian.org/692283 Severity, certainty: serious, possible syntax-error-in-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Value of the Plural-Forms header field could not be parsed. (But there are no translated messages which use plural forms.) It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: important, certain trailing-junk-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field contains unexpected text after the plural expression. GNU gettext runtime ignores such trailing junk, but other header parsers might be less liberal in what they accept. Severity, certainty: important, certain translation-in-template ~~~~~~~~~~~~~~~~~~~~~~~ The PO template file contains a translated message. Severity, certainty: minor, certain unable-to-determine-language ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ i18nspector was unable to determine language of this file. Absence of this information will prevent it from performing further checks. Severity, certainty: normal, wild-guess unexpected-flag-for-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An unexpected flag is associated with the header entry. The only flag that makes sense for the header entry is ``fuzzy``. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: normal, possible unknown-encoding ~~~~~~~~~~~~~~~~ This file declares an encoding that couldn't be recognized by i18nspector. It might be a typo. Absence of encoding information will prevent i18nspector from performing further checks. Severity, certainty: important, possible unknown-file-type ~~~~~~~~~~~~~~~~~ File format of this file couldn't be recognized. It might be a bug in i18nspector. Severity, certainty: normal, wild-guess unknown-header-field ~~~~~~~~~~~~~~~~~~~~ The header field name is unknown to i18nspector. It might be a typo or a capitalization error (header field names are case-sensitive). References: | https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html Severity, certainty: minor, wild-guess unknown-message-flag ~~~~~~~~~~~~~~~~~~~~ An unknown flag is associated with one of the messages. It might be a typo. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: normal, wild-guess unknown-poedit-language ~~~~~~~~~~~~~~~~~~~~~~~ Language declared in X-Poedit-Language couldn't be recognized. It might be a bug in i18nspector. Severity, certainty: minor, wild-guess unrepresentable-characters ~~~~~~~~~~~~~~~~~~~~~~~~~~ The declared encoding cannot represent all characters commonly used in this language. This is a strong indication that the declared encoding is incorrect. Severity, certainty: serious, possible unusual-character-in-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The header entry contains an unusual character. This is usually an indication of an encoding problem, such as: * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. References: | https://www.unicode.org/faq/utf_bom.html#bom6 Severity, certainty: important, certain unusual-character-in-translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One of the translated messages contains an unusual character. This is usually an indication of an encoding problem, such as: * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. References: | https://www.unicode.org/faq/utf_bom.html#bom6 Severity, certainty: important, possible unusual-plural-forms ~~~~~~~~~~~~~~~~~~~~ The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. Severity, certainty: serious, possible unusual-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. (But there are no translated messages which use plural forms.) Severity, certainty: normal, possible i18nspector-0.27.1/doc/todo0000644000000000000000000001544714275257143015440 0ustar00rootroot00000000000000Add more ``Plural-Forms``. Document how the current ``Plural-Forms`` were obtained. * https://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html?id=l10n/pluralforms * https://unicode.org/cldr/trac/browser/trunk/common/supplemental/plurals.xml Complain about incorrect locale codes: * https://www.loc.gov/standards/iso639-2/php/code_changes.php * ``al`` → ``sq`` * ``bh`` → ``bho`` | ``mai`` | ``mag`` * ``ca-XV`` → ``ca@valencia`` * ``cn`` → ``zh`` * ``cz`` → ``cs`` * ``dk`` → ``da`` * ``en_AM`` → ``en_US`` * ``en_BR`` → ``en_GB`` * ``en_UK`` → ``en_GB`` * ``gr`` → ``el`` * ``in`` → ``id`` * ``iw`` → ``he`` * ``ji`` → ``yi`` * ``jw`` → ``jv`` * ``mo`` → ``ro_MD`` * ``no`` → ``nb`` * ``sh_BA`` → ``bs_BA`` * ``sh_HR`` → ``hr_HR`` * ``sh_RS`` → ``sr_RS`` * ``sr@Latn`` → ``sr@latin`` * ``sr_CS`` → ``sr`` * ``sr_SR`` → ``sr_RS`` * ``sr_YU`` → ``sr`` * ``uk_UK`` → ``uk_UA`` * ``vn`` → ``vi`` Correct locale codes in invalid format, e.g.: * ``da-DK`` → ``da_DK``: https://sources.debian.org/data/main/d/debian-handbook/7.20140126~deb7u1/da-DK/00a_preface.po * ``pt_br`` → ``pt_BR``: https://sources.debian.org/data/main/p/pam-pkcs11/0.6.8-1/po/pt_br.po * ``Pt`` → ``pt``: https://sources.debian.org/data/main/d/darcsweb/1.1-3.1/debian/po/pt.po Correct ``Language`` with both a natural language and a language code, e.g.: * ``nl (Dutch)``: https://sources.debian.org/data/main/g/garcon/0.1.12-1/po/nl.po * ``Serbian (sr)``: https://sources.debian.org/data/main/a/at-spi2-atk/2.5.3-2/po/sr.po Guess language from ``Language-Team``. * https://translationproject.org/team/ Guess language from the filename even when it includes encoding. Test-cases: * https://sources.debian.org/src/vim/2:7.3.547-7/src/po/ Add ``characters=``\ … for more languages. Document how the current values were obtained. Fix support for ``X-Poedit-Language: (Afan) Oromo``. Fix support for ``X-Poedit-Language: Serbian (Latin)``. Document the security model. Add tests for: * Debian source packages * Debian binary packages * MO files (at least against some tags) * languages with multiple correct ``Plural-Forms`` * lib.moparser * all non-Python encodings * 0x5C byte as a part of a multibyte character: https://sources.debian.org/src/vim/2:7.3.547-7/src/po/zh_TW.po/#L13 * SHIFT_JIS encoding: https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/po-lex.c?id=v0.18.3#n179 Detect question marks in unusual places. Add support for configuration files. Once it's implemented: * Disable ``--pedantic`` by default. Add support for profiles: severity of a tag may depend on whether you are upstream, a translator, or a user. Add support for overrides. Add option for disabling/forcing colored output. Use `blessings `_ for colored output. Reimplement the EUC-TW codec with PyICU. Check for hardcoded Language in POT files. Add option for printing tag descriptions. When emitting ``encoding-in-language-header-field``, check if the encoding matches the one from ``Content-Type``. Test-cases: * https://sources.debian.org/data/main/r/rhn-client-tools/1.8.9-3/po/zh_CN.GB2312.po Split ``no-email-address-in-last-translator`` from ``invalid-last-translator``. Test-cases: * https://sources.debian.org/data/main/m/mtpaint/3.40-1/po/de.po * https://sources.debian.org/data/main/y/yaboot-installer/1.1.26/debian/po/hi.po Split ``missing-timezone-in-date`` from ``invalid-date``. Check for non-ASCII (translated?) project id. Test-case: * https://sources.debian.org/data/main/a/alarm-clock/1.2.5-1.2/po/sr.po Check for localized boilerplate in headers. Decide what to do with commas in ``Last-Translator``: either accept them, or provide a better error message. Test-case: * https://sources.debian.org/data/main/i/installation-guide/20130503/po/zh_TW/using-d-i.po polib PO encoding detection is not robust enough. Test-case: ``xfail-header-imitation.po`` Add support for system-dependent messages (minor revision 1). Check for PO files that are not encoding-aware: * https://marc.info/?l=openbsd-ports&m=98988950322667&w=2 Add support for MediaWiki Translate's ``invalid-plural`` flag. Test-case: * https://sources.debian.org/data/main/e/evolution/3.4.4-3/po/fi.po Add support for pygettext's ``docstring`` flag. Check .desktop files: * https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s04.html Check Shared Mime Info files: * https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html Figure out what to do with software that call ``gettext("")`` intentionally. Test-case: * https://sources.debian.org/src/evolution/3.4.4-3/shell/main.c/#L579 Check for ``msgstr_plural`` without ``msgstr[N]``, and other way round. Verify that if *n* = plural(1) = plural(*i*) for some *i* > 1, then msgstr[*n*] distinguishes singular and plural forms, even when no numeral is involved. * https://bugs.debian.org/753946#51 Add support for more string formats (in order of popularity on GitHub):: php-format javascript-format perl-format java-format csharp-format kde-format sh-format qt-format tcl-format perl-brace-format scheme-format ycp-format lisp-format awk-format objc-format object-pascal-format librep-format smalltalk-format boost-format qt-plural-format lua-format kde-kuit gfc-internal-format gcc-internal-format elisp-format Improve C format string checks: * Check for the ``I`` C format string flag in msgid. * Recognize type mismatch between ``%*d%d`` and ``%d%*d``. * Make sure ``%%`` is treated as text wrt. omitting integer conversion. SHIFT_JIS and JOHAB encodings are broken in Python; or at least they are not compatible with glibc. Implement a work-around. Test-case:: assert b'\\'.decode('SHIFT_JIS') == '\N{YEN SIGN}' assert b'\\'.decode('JOHAB') == '\N{WON SIGN}' Timezone abbreviations not only are not unique, but also can change their meaning over time. * https://mm.icann.org/pipermail/tz/2014-June/021089.html Check for capitalization inconsistencies between msgid and msgstr. Language codes for some locales supported by glibc aren't recognized:: ayc ber brx cmn hak hne lij lzh mhr nan nhn pap quz shs szl the unm wae yue The tag name ``invalid-language`` might be misleading. Rename or split it. Check for ``li.org`` mailing lists in ``Language-Team``. * https://lists.gnu.org/archive/html/bug-gettext/2016-02/msg00003.html Add support for xgettext message syntax check flags: * https://git.savannah.gnu.org/cgit/gettext.git/commit/?id=d9fc3d2a3f43 Investigate possible bugs in PO editors: * Virtaal (0.7.1) leaves stray previous msgid. https://bugs.debian.org/809522 * Lokalize (1.4) leaves stray previous msgid. .. vim:ft=rst ts=3 sts=3 sw=3 i18nspector-0.27.1/i18nspector0000755000000000000000000000546714275257143016111 0ustar00rootroot00000000000000#!/usr/bin/env python3 # encoding=UTF-8 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' checking tool for gettext POT, PO and MO files ''' import os import sys # pylint: disable=consider-using-f-string # ---------------------------------------- def error(message): try: import argparse # pylint: disable=import-outside-toplevel ap = argparse.ArgumentParser() prog = ap.prog except ImportError: import optparse # pylint: disable=deprecated-module,import-outside-toplevel ap = optparse.OptionParser() prog = ap.get_prog_name() message = str.join('', (prog, ': error: ', message, '\n')) ap.exit(1, message) def require_python(*version): if sys.version_info < version: version_str = str.join('.', map(str, version)) message = 'Python >= %s is required' % version_str error(message) def require_polib(*version): import polib # pylint: disable=import-outside-toplevel polib_version = tuple( int(x) for x in polib.__version__.split('.') ) if polib_version < version: version_str = str.join('.', map(str, version)) message = 'polib >= {ver} is required'.format(ver=version_str) error(message) require_python(3, 6) require_polib(1, 0, 0) # ---------------------------------------- basedir_fallback = None basedir = os.environ.get('I18NSPECTOR_BASEDIR', basedir_fallback) if basedir is None: basedir = os.path.dirname( os.path.realpath(__file__) ) basedir = os.path.join(basedir, '') os.stat(basedir) sys.path[:0] = [basedir] # pylint: disable=wrong-import-position from lib import paths assert os.path.samefile(basedir, paths.basedir) from lib import cli cli.__doc__ = (__doc__ or '').strip() cli.main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/0000755000000000000000000000000014275257160014535 5ustar00rootroot00000000000000i18nspector-0.27.1/lib/__init__.py0000644000000000000000000000011514275257143016644 0ustar00rootroot00000000000000''' i18nspector's private modules ''' int(0_0) # Python >= 3.6 is required i18nspector-0.27.1/lib/check/0000755000000000000000000000000014275257143015613 5ustar00rootroot00000000000000i18nspector-0.27.1/lib/check/__init__.py0000644000000000000000000013323414275257143017732 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' checks ''' import abc import collections import difflib import email.utils import heapq import os import re import types import urllib.parse import polib from lib import domains from lib import encodings as encinfo from lib import gettext from lib import ling from lib import misc from lib import polib4us from lib import tags from lib import xml from lib.check.msgformat import c as msgformat_c from lib.check.msgformat import perlbrace as msgformat_perlbrace from lib.check.msgformat import pybrace as msgformat_pybrace from lib.check.msgformat import python as msgformat_python from lib.check.msgrepr import message_repr class EnvironmentNotPatched(RuntimeError): pass class EnvironmentAlreadyPatched(RuntimeError): pass find_unusual_characters = re.compile( r'[\x00-\x08\x0B-\x1A\x1C-\x1F]' # C0 except TAB, LF, ESC r'|\x1B(?!\[)' # ESC, except when followed by [ r'|\x7F' # DEL r'|[\x80-\x9F]' # C1 '|\uFEFF' # ZERO WIDTH NO-BREAK SPACE '|\uFFFD' # REPLACEMENT CHARACTER '|[\uFFFE\uFFFF]' # non-characters r'|(?<=\w)\xBF' # INVERTED QUESTION MARK but only directly after a letter ).findall header_fields_with_dedicated_checks = set() def checks_header_fields(*fields): def identity(x): return x header_fields_with_dedicated_checks.update(fields) return identity class Checker(metaclass=abc.ABCMeta): _patched_environment = None @classmethod def patch_environment(cls): if cls._patched_environment is not None: raise EnvironmentAlreadyPatched encinfo.install_extra_encodings() polib4us.install_patches() cls._patched_environment = True def __init__(self, path, *, options): if self._patched_environment is not True: raise EnvironmentNotPatched self.path = path self.fake_path = path if options.fake_root is not None: (real_root, fake_root) = options.fake_root if not real_root.endswith(os.sep): raise ValueError if not fake_root.endswith(os.sep): raise ValueError if path.startswith(real_root): self.fake_path = fake_root + path[len(real_root):] self.options = options self._message_format_checkers = { 'c': msgformat_c.Checker(self), 'perl-brace': msgformat_perlbrace.Checker(self), 'python': msgformat_python.Checker(self), 'python-brace': msgformat_pybrace.Checker(self), } @abc.abstractmethod def tag(self, tagname, *extra): pass def check(self): # If a file passed to polib doesn't exist, it will “helpfully” treat it # as PO/MO file _contents_. This is definitely not what we want. To # prevent such disaster, fail early if the file doesn't exit. try: os.stat(self.path) except OSError as exc: self.tag('os-error', tags.safestr(exc.strerror)) return if self.options.file_type is None: extension = os.path.splitext(self.path)[-1] else: extension = '.' + self.options.file_type is_template = False is_binary = False if extension == '.po': constructor = polib.pofile elif extension == '.pot': constructor = polib.pofile is_template = True elif extension in {'.mo', '.gmo'}: constructor = polib.mofile is_binary = True else: self.tag('unknown-file-type') return broken_encoding = False try: try: file = constructor(self.path) except UnicodeDecodeError as exc: broken_encoding = exc file = constructor(self.path, encoding='ISO-8859-1') except polib4us.moparser.SyntaxError as exc: self.tag('invalid-mo-file', tags.safestr(exc)) return except OSError as exc: message = str(exc) if exc.errno is not None: self.tag('os-error', tags.safestr(exc.strerror)) return elif message.startswith('Syntax error in po file '): message = message[24:] message_parts = [] if message.startswith(self.path + ' '): message = message[len(self.path)+1:] match = re.match(r'^\(line ([0-9]+)\)(?:: (.+))?$', message) if match is not None: lineno_part = f'line {match.group(1)}' message = match.group(2) if message is not None: lineno_part += ':' if re.match(r'^[a-z]+( [a-z]+)*$', message): message = tags.safestr(message) message_parts += [tags.safestr(lineno_part)] if message is not None: message_parts += [message] self.tag('syntax-error-in-po-file', *message_parts) return raise finally: if broken_encoding: # pylint: disable=no-member s = broken_encoding.object assert isinstance(s, bytes) begin = max(broken_encoding.start - 40, 0) end = broken_encoding.start + 40 s = s[begin:end] self.tag('broken-encoding', s, tags.safestr('cannot be decoded as'), broken_encoding.encoding.upper(), ) # pylint: enable=no-member broken_encoding = True ctx = types.SimpleNamespace() ctx.file = file ctx.is_template = is_template ctx.is_binary = is_binary self.check_comments(ctx) self.check_headers(ctx) self.check_language(ctx) self.check_plurals(ctx) self.check_mime(ctx) if broken_encoding: ctx.encoding = None self.check_dates(ctx) self.check_project(ctx) self.check_translator(ctx) self.check_messages(ctx) def check_comments(self, ctx): regexs = { r'\bPACKAGE package\b', r'\bCopyright \S+ YEAR\b', r"\bTHE PACKAGE'S COPYRIGHT HOLDER\b", } if not ctx.is_template: regexs |= { r'\bFIRST AUTHOR\b', r'', r'(?<=>), YEAR\b', } regex = re.compile(str.join('|', regexs)) for line in ctx.file.header.splitlines(): match = regex.search(line) if match is None: continue self.tag('boilerplate-in-initial-comments', line) @checks_header_fields('Language', 'X-Poedit-Language', 'X-Poedit-Country') def check_language(self, ctx): ctx.language = None duplicate_meta_language = False meta_languages = ctx.metadata['Language'] if len(meta_languages) > 1: self.tag('duplicate-header-field-language') meta_languages = sorted(set(meta_languages)) if len(meta_languages) > 1: duplicate_meta_language = True if len(meta_languages) == 1: [meta_language] = meta_languages else: meta_language = None orig_meta_language = meta_language if ctx.is_template: if meta_language is None: self.tag('no-language-header-field') return language = self.options.language language_source = 'command-line' language_source_quality = 1 if language is None: path_components = os.path.normpath(self.path).split('/') try: i = path_components.index('LC_MESSAGES') except ValueError: i = 0 if i > 0: language = path_components[i - 1] try: language = ling.parse_language(language) language.fix_codes() language.remove_encoding() language.remove_nonlinguistic_modifier() except ling.LanguageError: # It's not our job to report possible errors in _pathnames_. language = None else: language_source = 'pathname' del path_components, i if language is None and self.path.endswith('.po'): language, ext = os.path.splitext(os.path.basename(self.path)) assert ext == '.po' try: language = ling.parse_language(language) if language.encoding is not None: # It's very likely that something else has been confused # for the apparent encoding. raise ling.LanguageError language.fix_codes() language.remove_nonlinguistic_modifier() except ling.LanguageError: # It's not our job to report possible errors in _pathnames_. language = None else: language_source = 'pathname' language_source_quality = 0 if meta_language: try: meta_language = ling.parse_language(meta_language) except ling.LanguageError: try: new_meta_language = ling.get_language_for_name(meta_language) except LookupError: new_meta_language = None if new_meta_language: self.tag('invalid-language', orig_meta_language, '=>', new_meta_language) else: self.tag('invalid-language', orig_meta_language) meta_language = new_meta_language if meta_language: if meta_language.remove_encoding(): self.tag('encoding-in-language-header-field', orig_meta_language) if meta_language.remove_nonlinguistic_modifier(): self.tag('language-variant-does-not-affect-translation', orig_meta_language) try: if meta_language.fix_codes(): self.tag('invalid-language', orig_meta_language, '=>', meta_language) except ling.LanguageError: self.tag('invalid-language', orig_meta_language) meta_language = None if language_source_quality <= 0 and ( f'/{meta_language}/' in self.path or f'/{meta_language}/'.replace('_', '-') in self.path ): # For LibreOffice, PO basename does not designate translation # language, but one of the path components does. # For example, # translations/source/da/dictionaries/pl_PL.po # is a Danish translation. language = None if meta_language: if language is None: language = meta_language language_source = 'Language header field' elif language != meta_language: self.tag('language-disparity', language, tags.safestr(f'({language_source})'), '!=', meta_language, tags.safestr('(Language header field)') ) poedit_languages = ctx.metadata['X-Poedit-Language'] if len(poedit_languages) > 1: self.tag('duplicate-header-field-x-poedit', 'X-Poedit-Language') poedit_languages = sorted(set(poedit_languages)) poedit_countries = ctx.metadata['X-Poedit-Country'] if len(poedit_countries) > 1: self.tag('duplicate-header-field-x-poedit', 'X-Poedit-Country') poedit_countries = sorted(set(poedit_countries)) if len(poedit_languages) == 1 and len(poedit_countries) <= 1: [poedit_language] = poedit_languages # FIXME: This should take also X-Poedit-Country into account. try: poedit_language = ling.get_language_for_name(poedit_language) except LookupError: self.tag('unknown-poedit-language', poedit_language) else: if language is None: language = poedit_language language_source = 'X-Poedit-Language header field' elif language.language_code != poedit_language.language_code: self.tag('language-disparity', language, tags.safestr(f'({language_source})'), '!=', poedit_language, tags.safestr('(X-Poedit-Language header field)') ) if language is None: if not orig_meta_language and not duplicate_meta_language: self.tag('no-language-header-field') self.tag('unable-to-determine-language') return if not orig_meta_language and not duplicate_meta_language: self.tag('no-language-header-field', tags.safestr('Language:'), language) ctx.language = language @checks_header_fields('Plural-Forms') def check_plurals(self, ctx): ctx.plural_preimage = None plural_forms = ctx.metadata['Plural-Forms'] if len(plural_forms) > 1: self.tag('duplicate-header-field-plural-forms') plural_forms = sorted(set(plural_forms)) if len(plural_forms) > 1: return if len(plural_forms) == 1: [plural_forms] = plural_forms else: assert len(plural_forms) == 0 plural_forms = None correct_plural_forms = None if ctx.language is not None: correct_plural_forms = ctx.language.get_plural_forms() has_plurals = False # messages with plural forms (translated or not)? expected_nplurals = {} # number of plurals in _translated_ messages for message in ctx.file: if message.obsolete: continue if message.msgid_plural is not None: has_plurals = True if not message.translated(): continue expected_nplurals[len(message.msgstr_plural)] = message if len(expected_nplurals) > 1: break if len(expected_nplurals) > 1: args = [] for n, message in sorted(expected_nplurals.items()): args += [n, message_repr(message, template='({})'), '!='] self.tag('inconsistent-number-of-plural-forms', *args[:-1]) if ctx.is_template: plural_forms_hint = 'nplurals=INTEGER; plural=EXPRESSION;' elif correct_plural_forms: plural_forms_hint = tags.safe_format( str.join(' or ', ('{}' for s in correct_plural_forms)), *correct_plural_forms ) else: plural_forms_hint = 'nplurals=; plural=' if plural_forms is None: if has_plurals: if expected_nplurals: self.tag('no-required-plural-forms-header-field', plural_forms_hint) else: self.tag('no-plural-forms-header-field', plural_forms_hint) return if ctx.is_template: return try: (n, expr, ljunk, rjunk) = gettext.parse_plural_forms(plural_forms, strict=False) except gettext.PluralFormsSyntaxError: if has_plurals: self.tag('syntax-error-in-plural-forms', plural_forms, '=>', plural_forms_hint) else: self.tag('syntax-error-in-unused-plural-forms', plural_forms, '=>', plural_forms_hint) return if ljunk: self.tag('leading-junk-in-plural-forms', ljunk) if rjunk: self.tag('trailing-junk-in-plural-forms', rjunk) if len(expected_nplurals) == 1: [expected_nplurals] = expected_nplurals.keys() if n != expected_nplurals: self.tag('incorrect-number-of-plural-forms', n, tags.safestr('(Plural-Forms header field)'), '!=', expected_nplurals, tags.safestr('(number of msgstr items)') ) locally_correct_n = locally_correct_expr = None if correct_plural_forms is not None: locally_correct_plural_forms = [ (i, expression) for i, expression in map(gettext.parse_plural_forms, correct_plural_forms) if i == n ] if not locally_correct_plural_forms: if has_plurals: self.tag('unusual-plural-forms', plural_forms, '=>', plural_forms_hint) else: self.tag('unusual-unused-plural-forms', plural_forms, '=>', plural_forms_hint) elif len(locally_correct_plural_forms) == 1: [[locally_correct_n, locally_correct_expr]] = locally_correct_plural_forms plural_preimage = collections.defaultdict(list) unusual_plural_forms = False codomain_limit = 200 try: for i in range(codomain_limit): fi = expr(i) if fi >= n: message = tags.safe_format(f'f({i}) = {fi} >= {n}') if has_plurals: self.tag('codomain-error-in-plural-forms', message) else: self.tag('codomain-error-in-unused-plural-forms', message) break plural_preimage[fi] += [i] if (n == locally_correct_n) and (fi != locally_correct_expr(i)) and (not unusual_plural_forms): if has_plurals: self.tag('unusual-plural-forms', plural_forms, '=>', plural_forms_hint) else: self.tag('unusual-unused-plural-forms', plural_forms, '=>', plural_forms_hint) unusual_plural_forms = True else: ctx.plural_preimage = dict(plural_preimage) except OverflowError: message = tags.safe_format('f({}): integer overflow', i) if has_plurals: self.tag('arithmetic-error-in-plural-forms', message) else: self.tag('arithmetic-error-in-unused-plural-forms', message) except ZeroDivisionError: message = tags.safe_format('f({}): division by zero', i) if has_plurals: self.tag('arithmetic-error-in-plural-forms', message) else: self.tag('arithmetic-error-in-unused-plural-forms', message) codomain = expr.codomain() if codomain is not None: (x, y) = codomain uncov_rngs = [] if x > 0: uncov_rngs += [range(0, x)] if y + 1 < n: uncov_rngs += [range(y + 1, n)] if (not uncov_rngs) and (ctx.plural_preimage is not None): period = expr.period() if period is None: period = (0, 1e999) if sum(period) < codomain_limit: for i in sorted(ctx.plural_preimage): if (i > 0) and (i - 1 not in ctx.plural_preimage): uncov_rngs += [range(i - 1, i)] break if (i + 1 < n) and (i + 1 not in ctx.plural_preimage): uncov_rngs += [range(i + 1, i + 2)] break for rng in uncov_rngs: rng = misc.format_range(rng, max=5) message = tags.safestr(f'f(x) != {rng}') if has_plurals: self.tag('codomain-error-in-plural-forms', message) else: self.tag('codomain-error-in-unused-plural-forms', message) ctx.plural_preimage = None @checks_header_fields('MIME-Version', 'Content-Transfer-Encoding', 'Content-Type') def check_mime(self, ctx): ctx.encoding = None # MIME-Version: mime_versions = ctx.metadata['MIME-Version'] if len(mime_versions) > 1: self.tag('duplicate-header-field-mime-version') mime_versions = sorted(set(mime_versions)) for mime_version in mime_versions: if mime_version != '1.0': self.tag('invalid-mime-version', mime_version, '=>', '1.0') if len(mime_versions) == 0: self.tag('no-mime-version-header-field', tags.safestr('MIME-Version: 1.0')) # Content-Transfer-Encoding: ctes = ctx.metadata['Content-Transfer-Encoding'] if len(ctes) > 1: self.tag('duplicate-header-field-content-transfer-encoding') ctes = sorted(set(ctes)) for cte in ctes: if cte != '8bit': self.tag('invalid-content-transfer-encoding', cte, '=>', '8bit') if len(ctes) == 0: self.tag('no-content-transfer-encoding-header-field', tags.safestr('Content-Transfer-Encoding: 8bit')) # Content-Type: cts = ctx.metadata['Content-Type'] if len(cts) > 1: self.tag('duplicate-header-field-content-type') cts = sorted(set(cts)) elif len(cts) == 0: content_type_hint = 'text/plain; charset=' self.tag('no-content-type-header-field', tags.safestr('Content-Type: ' + content_type_hint)) return encodings = set() for ct in cts: content_type_hint = 'text/plain; charset=' match = re.search(r'(\Atext/plain; )?\bcharset=([^\s;]+)\Z', ct) if match: encoding = match.group(2) try: is_ascii_compatible = encinfo.is_ascii_compatible_encoding(encoding, missing_ok=False) except encinfo.EncodingLookupError: if encoding == 'CHARSET': if not ctx.is_template: self.tag('boilerplate-in-content-type', ct) else: self.tag('unknown-encoding', encoding) encoding = None else: if not is_ascii_compatible: self.tag('non-ascii-compatible-encoding', encoding) elif encinfo.is_portable_encoding(encoding): pass else: new_encoding = encinfo.propose_portable_encoding(encoding) if new_encoding is not None: self.tag('non-portable-encoding', encoding, '=>', new_encoding) encoding = new_encoding else: self.tag('non-portable-encoding', encoding) if ctx.language is not None: unrepresentable_characters = ctx.language.get_unrepresentable_characters(encoding) if unrepresentable_characters: if len(unrepresentable_characters) > 5: unrepresentable_characters[4:] = ['...'] self.tag('unrepresentable-characters', encoding, *unrepresentable_characters) if match.group(1) is None: if encoding is not None: content_type_hint = content_type_hint.replace('', encoding) self.tag('invalid-content-type', ct, '=>', content_type_hint) if encoding is not None: encodings.add(encoding) else: self.tag('invalid-content-type', ct, '=>', content_type_hint) if len(encodings) == 1: [ctx.encoding] = encodings @checks_header_fields('POT-Creation-Date', 'PO-Revision-Date') def check_dates(self, ctx): try: content_type = ctx.metadata['Content-Type'][0] except IndexError: content_type = '' is_publican = content_type.startswith('application/x-publican;') for field in 'POT-Creation-Date', 'PO-Revision-Date': dates = ctx.metadata[field] if len(dates) > 1: self.tag('duplicate-header-field-date', field) dates = sorted(set(dates)) elif len(dates) == 0: if field.startswith('POT-') and ctx.is_binary: # In gettext >> 0.19.8.1, msgfmt will be removing # the POT-Creation-Date header. # https://savannah.gnu.org/bugs/?49654 continue self.tag('no-date-header-field', field) continue for date in dates: if ctx.is_template and field.startswith('PO-') and (date == gettext.boilerplate_date): continue if 'T' in date and is_publican: # Publican uses DateTime->now(), which uses the UTC timezone by default: # https://sources.debian.org/src/publican/2.8-3/lib/Publican/Translate.pm/?hl=748#L744 # https://bugs.debian.org/714739 tz_hint = '-0000' else: tz_hint = None try: fixed_date = gettext.fix_date_format(date, tz_hint=tz_hint) except gettext.BoilerplateDate: self.tag('boilerplate-in-date', tags.safestr(field + ':'), date) continue except gettext.DateSyntaxError: self.tag('invalid-date', tags.safestr(field + ':'), date) continue else: if date != fixed_date: self.tag('invalid-date', tags.safestr(field + ':'), date, '=>', fixed_date) stamp = gettext.parse_date(fixed_date) if stamp > misc.utc_now(): self.tag('date-from-future', tags.safestr(field + ':'), date) if stamp < gettext.epoch: self.tag('ancient-date', tags.safestr(field + ':'), date) @checks_header_fields('Project-Id-Version', 'Report-Msgid-Bugs-To') def check_project(self, ctx): # Project-Id-Version: project_id_versions = ctx.metadata['Project-Id-Version'] if len(project_id_versions) > 1: self.tag('duplicate-header-field-project-id-version') project_id_versions = sorted(set(project_id_versions)) elif len(project_id_versions) == 0: self.tag('no-project-id-version-header-field') for project_id_version in project_id_versions: if project_id_version in {'PACKAGE VERSION', 'PROJECT VERSION'}: self.tag('boilerplate-in-project-id-version', project_id_version) else: if not re.search(r'[^_\d\W]', project_id_version): self.tag('no-package-name-in-project-id-version', project_id_version) if not re.search(r'[0-9]', project_id_version): self.tag('no-version-in-project-id-version', project_id_version) # Report-Msgid-Bugs-To: report_msgid_bugs_tos = ctx.metadata['Report-Msgid-Bugs-To'] if len(report_msgid_bugs_tos) > 1: self.tag('duplicate-header-field-report-msgid-bugs-to') report_msgid_bugs_tos = sorted(set(report_msgid_bugs_tos)) if report_msgid_bugs_tos == ['']: report_msgid_bugs_tos = [] if len(report_msgid_bugs_tos) == 0: self.tag('no-report-msgid-bugs-to-header-field') for report_msgid_bugs_to in report_msgid_bugs_tos: real_name, email_address = email.utils.parseaddr(report_msgid_bugs_to) del real_name if '@' not in email_address: uri = urllib.parse.urlparse(report_msgid_bugs_to) if uri.scheme == '': self.tag('invalid-report-msgid-bugs-to', report_msgid_bugs_to) elif domains.is_email_in_special_domain(email_address): self.tag('invalid-report-msgid-bugs-to', report_msgid_bugs_to) elif email_address == 'EMAIL@ADDRESS': self.tag('boilerplate-in-report-msgid-bugs-to', report_msgid_bugs_to) elif domains.is_email_in_dotless_domain(email_address): self.tag('invalid-report-msgid-bugs-to', report_msgid_bugs_to) @checks_header_fields('Last-Translator', 'Language-Team') def check_translator(self, ctx): # Last-Translator: translators = ctx.metadata['Last-Translator'] if len(translators) > 1: self.tag('duplicate-header-field-last-translator') translators = sorted(set(translators)) elif len(translators) == 0: self.tag('no-last-translator-header-field') translator_emails = {} for translator in translators: translator_name, translator_email = email.utils.parseaddr(translator) del translator_name translator_emails[translator_email] = translator if '@' not in translator_email: self.tag('invalid-last-translator', translator) elif domains.is_email_in_special_domain(translator_email): self.tag('invalid-last-translator', translator) elif translator_email == 'EMAIL@ADDRESS': if not ctx.is_template: self.tag('boilerplate-in-last-translator', translator) elif domains.is_email_in_dotless_domain(translator_email): self.tag('invalid-last-translator', translator) # Language-Team: teams = ctx.metadata['Language-Team'] if len(teams) > 1: self.tag('duplicate-header-field-language-team') teams = sorted(set(teams)) elif len(teams) == 0: self.tag('no-language-team-header-field') for team in teams: team_name, team_email = email.utils.parseaddr(team) del team_name if '@' not in team_email: # TODO: A URL is also allowed here. # self.tag('invalid-language-team', translator) pass elif domains.is_email_in_special_domain(team_email): self.tag('invalid-language-team', team) elif team_email in {'LL@li.org', 'EMAIL@ADDRESS'}: if not ctx.is_template: self.tag('boilerplate-in-language-team', team) elif domains.is_email_in_dotless_domain(team_email): self.tag('invalid-language-team', team) else: translator = translator_emails.get(team_email) if translator is not None: self.tag('language-team-equal-to-last-translator', team, translator) def check_headers(self, ctx): metadata = collections.defaultdict(list) strays = [] ctx.file.header_entry = None seen_header_entry = False for entry in ctx.file: if not is_header_entry(entry) or entry.obsolete: continue if seen_header_entry: self.tag('duplicate-header-entry') break if entry.occurrences: self.tag('empty-msgid-message-with-source-code-references', *(str.join(':', (path, line)) for path, line in entry.occurrences) ) if entry.msgid_plural is not None: self.tag('empty-msgid-message-with-plural-forms') msgstr = entry.msgstr_plural.get(0, entry.msgstr) # At least in polib 1.0.0, if the source PO file is empty, # msgstr for the header entry is None. msgstr = msgstr or '' for line in gettext.parse_header(msgstr): if isinstance(line, dict): [(key, value)] = line.items() metadata[key] += [value] else: strays += [line] flags = collections.Counter(entry.flags) for flag, n in sorted(flags.items()): if flag == 'fuzzy': if not ctx.is_template: self.tag('fuzzy-header-entry') elif difflib.get_close_matches(flag.lower(), ['fuzzy'], cutoff=0.8): self.tag('unexpected-flag-for-header-entry', flag, '=>', 'fuzzy') else: self.tag('unexpected-flag-for-header-entry', flag) if n > 1: self.tag('duplicate-flag-for-header-entry', flag) if entry is not ctx.file[0]: self.tag('distant-header-entry') unusual_chars = set(find_unusual_characters(msgstr)) if unusual_chars: unusual_char_names = str.join(', ', ( f'U+{ord(ch):04X} {encinfo.get_character_name(ch)}' for ch in sorted(unusual_chars) )) self.tag('unusual-character-in-header-entry', tags.safestr(unusual_char_names)) seen_header_entry = True seen_conflict_marker = False for stray in strays: if gettext.search_for_conflict_marker(stray): if not seen_conflict_marker: self.tag('conflict-marker-in-header-entry', stray) seen_conflict_marker = True else: self.tag('stray-header-line', stray) header_fields = frozenset(gettext.header_fields) header_fields_lc = {str.lower(s): s for s in header_fields} for key, values in sorted(metadata.items()): if key.startswith(('X-', 'x-')): pass # ok elif key in header_fields: pass # ok else: hint = header_fields_lc.get(key.lower()) if hint is None: hints = difflib.get_close_matches(key, header_fields, n=1, cutoff=0.8) if hints: [hint] = hints if hint in metadata: hint = None if hint is None: self.tag('unknown-header-field', key) else: self.tag('unknown-header-field', key, '=>', hint) if len(values) > 1 and key not in header_fields_with_dedicated_checks: self.tag('duplicate-header-field', key) ctx.metadata = metadata del ctx.file.metadata del ctx.file.metadata_is_fuzzy def check_messages(self, ctx): found_unusual_characters = set() msgid_counter = collections.Counter() for message in ctx.file: if message.obsolete: continue if is_header_entry(message): continue flags = self._check_message_flags(message) self._check_message_formats(ctx, message, flags) msgid_counter[message.msgid, message.msgctxt] += 1 if msgid_counter[message.msgid, message.msgctxt] == 2: self.tag('duplicate-message-definition', message_repr(message)) has_msgstr = bool(message.msgstr) has_msgstr_plural = any(message.msgstr_plural.values()) if ctx.is_template: if has_msgstr or has_msgstr_plural: self.tag('translation-in-template', message_repr(message)) leading_lf = message.msgid.startswith('\n') trailing_lf = message.msgid.endswith('\n') has_previous_msgid = any(s is not None for s in [ message.previous_msgctxt, message.previous_msgid, message.previous_msgid_plural, ]) if has_previous_msgid and not flags.fuzzy: self.tag('stray-previous-msgid', message_repr(message)) strings = [] if message.msgid_plural is not None: strings += [message.msgid_plural] if not flags.fuzzy: if has_msgstr: strings += [message.msgstr] if has_msgstr_plural: strings += message.msgstr_plural.values() # the order doesn't matter here for s in strings: if s.startswith('\n') != leading_lf: self.tag('inconsistent-leading-newlines', message_repr(message)) break for s in strings: if s.endswith('\n') != trailing_lf: self.tag('inconsistent-trailing-newlines', message_repr(message)) break strings = [] if has_msgstr: strings += [message.msgstr] if has_msgstr_plural: strings += misc.sorted_vk(message.msgstr_plural) if ctx.encoding is not None: msgid_uc = ( set(find_unusual_characters(message.msgid)) | set(find_unusual_characters(message.msgid_plural or '')) ) for msgstr in strings: msgstr_uc = set(find_unusual_characters(msgstr)) uc = msgstr_uc - msgid_uc - found_unusual_characters if not uc: continue names = str.join(', ', ( f'U+{ord(ch):04X} {encinfo.get_character_name(ch)}' for ch in sorted(uc) )) self.tag('unusual-character-in-translation', message_repr(message, template='{}:'), tags.safestr(names) ) found_unusual_characters |= uc if not flags.fuzzy: for msgstr in strings: conflict_marker = gettext.search_for_conflict_marker(msgstr) if conflict_marker is not None: conflict_marker = conflict_marker.group(0) self.tag('conflict-marker-in-translation', message_repr(message), conflict_marker) break if has_msgstr_plural and not all(message.msgstr_plural.values()): self.tag('partially-translated-message', message_repr(message)) if len(msgid_counter) == 0: possible_hidden_strings = False if ctx.is_binary: possible_hidden_strings = ctx.file.possible_hidden_strings if not possible_hidden_strings: self.tag('empty-file') def _check_message_flags(self, message): info = types.SimpleNamespace() info.fuzzy = False info.range_min = 0 info.range_max = 1e999 # +inf info.formats = None flags = collections.Counter(message.flags) wrap = None format_flags = collections.defaultdict(dict) range_flags = collections.defaultdict( collections.Counter ) for flag, n in sorted(flags.items()): known_flag = True if flag == 'fuzzy': info.fuzzy = True elif flag in {'wrap', 'no-wrap'}: new_wrap = flag == 'wrap' if wrap == (not new_wrap): self.tag('conflicting-message-flags', message_repr(message, template='{}:'), 'wrap', 'no-wrap' ) else: wrap = new_wrap elif flag.startswith('range:'): if message.msgid_plural is None: self.tag('range-flag-without-plural-string') match = re.match(r'\A([0-9]+)[.][.]([0-9]+)\Z', flag[6:].strip(' \t\r\f\v')) if match is not None: i, j = map(int, match.groups()) if i < j: info.range_min = i info.range_max = j else: match = None if match is None: self.tag('invalid-range-flag', message_repr(message, template='{}:'), flag ) else: range_flags[i, j][flag] += n n = 0 elif flag.endswith('-format'): known_flag = False for prefix in 'no-', 'possible-', 'impossible-', '': tp = prefix.rstrip('-') if not flag.startswith(prefix): continue string_format = flag[len(prefix):-7] if string_format in gettext.string_formats: known_flag = True format_flags[tp][string_format] = flag break elif flag == 'markdown-text': # supported by: # * po4a >= 0.58: # https://github.com/mquinson/po4a/commit/08f93cbe0cc0bcf1 # * weblate >= 4.0: # https://github.com/WeblateOrg/weblate/commit/8832525871c07779 pass else: known_flag = False if not known_flag: self.tag('unknown-message-flag', message_repr(message, template='{}:'), flag ) if n > 1 and flag: self.tag('duplicate-message-flag', message_repr(message, template='{}:'), flag ) if len(range_flags) > 1: [range1, range2] = heapq.nsmallest(2, range_flags.keys()) self.tag('conflicting-message-flags', message_repr(message, template='{}:'), min(range_flags[range1].keys()), min(range_flags[range2].keys()), ) elif len(range_flags) == 1: [range_flags] = range_flags.values() if sum(range_flags.values()) > 1: self.tag('duplicate-message-flag', message_repr(message, template='{}:'), min(range_flags.keys()) ) positive_format_flags = format_flags[''] info.formats = frozenset(positive_format_flags) for fmt1, flag1 in sorted(positive_format_flags.items()): for fmt2, flag2 in sorted(positive_format_flags.items()): if fmt1 >= fmt2: continue fmt_ex1 = gettext.string_formats[fmt1] fmt_ex2 = gettext.string_formats[fmt2] if fmt_ex1 & fmt_ex2: # the formats are, at least to some extent, compatible continue self.tag('conflicting-message-flags', message_repr(message, template='{}:'), flag1, flag2 ) for positive_key, negative_key in [('', 'no'), ('', 'impossible'), ('possible', 'impossible')]: positive_format_flags = format_flags[positive_key] negative_format_flags = format_flags[negative_key] conflicting_formats = frozenset(positive_format_flags) & frozenset(negative_format_flags) for fmt in sorted(conflicting_formats): self.tag('conflicting-message-flags', message_repr(message, template='{}:'), positive_format_flags[fmt], negative_format_flags[fmt], ) positive_format_flags = format_flags[''] possible_format_flags = format_flags['possible'] redundant_formats = frozenset(positive_format_flags) & frozenset(possible_format_flags) for fmt in sorted(redundant_formats): self.tag('redundant-message-flag', message_repr(message, template='{}:'), possible_format_flags[fmt], tags.safe_format(f'(implied by {positive_format_flags[fmt]})') ) return info def _check_message_formats(self, ctx, message, flags): for fmt in sorted(flags.formats): try: checker = self._message_format_checkers[fmt] except KeyError: continue checker.check_message(ctx, message, flags) if re.match(fr'\Atype: Content of: (<{xml.name_re}>)+\Z', message.comment or ''): self._check_message_xml_format(ctx, message, flags) def _check_message_xml_format(self, ctx, message, flags): if ctx.encoding is None: return prefix = message_repr(message, template='{}:') try: xml.check_fragment(message.msgid) except xml.SyntaxError as exc: if ctx.is_template: self.tag('malformed-xml', prefix, tags.safestr(exc)) return if flags.fuzzy: return if not message.msgstr: return try: xml.check_fragment(message.msgstr) except xml.SyntaxError as exc: self.tag('malformed-xml', prefix, tags.safestr(exc)) __all__ = ['Checker'] def is_header_entry(entry): return ( entry.msgid == '' and entry.msgctxt is None ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/check/msgformat/0000755000000000000000000000000014275257143017612 5ustar00rootroot00000000000000i18nspector-0.27.1/lib/check/msgformat/__init__.py0000644000000000000000000001545314275257143021733 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks ''' import abc import types class Checker(metaclass=abc.ABCMeta): def __init__(self, parent): self.parent = parent @property @abc.abstractmethod def backend(self): pass def tag(self, tagname, *extra): return self.parent.tag(tagname, *extra) def check_message(self, ctx, message, flags): msgids = [message.msgid] if message.msgid_plural is not None: msgids += [message.msgid_plural] msgid_fmts = {} for i, s in enumerate(msgids): if ctx.is_template: fmt = self.check_string(ctx, message, s) else: try: fmt = self.backend.FormatString(s) except self.backend.Error: # If msgid isn't even a valid format string, then # reporting errors against msgstr is not worth the trouble. return if fmt is not None: msgid_fmts[i] = fmt if ctx.is_template and (len(msgid_fmts) == 2): self.check_args( message, 'msgid_plural', msgid_fmts[1], 'msgid', msgid_fmts[0], omitted_int_conv_ok=True, ) self.check_msgids(message, msgid_fmts) if flags.fuzzy: return if ctx.encoding is None: return has_msgstr = bool(message.msgstr) has_msgstr_plural = any(message.msgstr_plural.values()) strings = [] if has_msgstr: d = types.SimpleNamespace() d.src_loc = 'msgid' d.src_fmt = msgid_fmts.get(0) d.dst_loc = 'msgstr' d.dst_fmt = self.check_string(ctx, message, message.msgstr) d.omitted_int_conv_ok = False strings += [d] if has_msgstr_plural and ctx.plural_preimage: for i, s in sorted(message.msgstr_plural.items()): assert isinstance(i, int) d = types.SimpleNamespace() msgid_fmt = msgid_fmts.get(0) msgid_plural_fmt = msgid_fmts.get(1) d.src_loc = 'msgid_plural' d.src_fmt = msgid_plural_fmt d.dst_loc = f'msgstr[{i}]' d.dst_fmt = self.check_string(ctx, message, s) if d.dst_fmt is None: continue try: preimage = ctx.plural_preimage[i] except KeyError: # broken plural forms continue preimage = [ x for x in preimage if flags.range_min <= x <= flags.range_max ] # XXX In theory, the msgstr[] corresponding to n=1 should # not have more arguments than msgid. In practice, it's not # uncommon to see something like this: # # Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; # # msgid "one byte" # msgid_plural "%d bytes" # msgstr[0] "%d bajt" # msgstr[1] "%d bajta" # msgstr[2] "%d bajtova" # # Here %d in msgstr[0] cannot be omitted, because it is used # not only for n=1, but also for n=21, n=31, and so on. # # To be pedantically correct, one could use a different # Plural-Forms, such that there is a separate value for n=1. # # See also: https://bugs.debian.org/753946 if preimage == [1]: # FIXME: “preimage” is not necessarily complete. # So it's theoretically possible that this msgstr[] # corresponds to both n=1 and another n. d.src_loc = 'msgid' d.src_fmt = msgid_fmt d.omitted_int_conv_ok = ( msgid_fmt is not None and msgid_plural_fmt is not None and len(msgid_fmt) == len(msgid_plural_fmt) # FIXME: The length equality is a rather weak indicator # that msgid and msgid_plural are equivalent. ) elif len(preimage) <= 1: d.omitted_int_conv_ok = True elif len(preimage) == 2 and preimage[0] == 0: # XXX In theory, the integer conversion should not be # omitted in the msgstr[] corresponding to both n=0 and # another n. In practice, it's sometimes obvious from # context that the message will never be used for n=0. d.omitted_int_conv_ok = True else: d.omitted_int_conv_ok = False strings += [d] for d in strings: if d.dst_fmt is None: continue if d.src_fmt is None: continue assert d.src_loc is not None assert d.dst_loc is not None self.check_args(message, d.src_loc, d.src_fmt, d.dst_loc, d.dst_fmt, omitted_int_conv_ok=d.omitted_int_conv_ok, ) def check_msgids(self, message, msgid_fmts): pass # no coverage @abc.abstractmethod def check_string(self, ctx, message, s): pass # no coverage @abc.abstractmethod def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): pass # no coverage __all__ = ['Checker'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/check/msgformat/c.py0000644000000000000000000001263614275257143020416 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: C ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import c as backend class Checker(CheckerBase): backend = backend # pylint: disable=self-assigning-variable def check_msgids(self, message, msgid_fmts): if msgid_fmts.get(0) is not None: try: [[arg]] = msgid_fmts[0].arguments except ValueError: pass else: if arg.type == 'int *': self.tag('qt-plural-format-mistaken-for-c-format', message_repr(message)) def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.MissingArgument as exc: self.tag('c-format-string-error', prefix, tags.safestr(exc.message), tags.safestr(f'{exc.args[1]}$'), ) except backend.ArgumentTypeMismatch as exc: self.tag('c-format-string-error', prefix, tags.safestr(exc.message), tags.safestr(f'{exc.args[1]}$'), tags.safestr(str.join(', ', sorted(x for x in exc.args[2]))), ) except backend.FlagError as exc: [conv, flag] = exc.args # pylint: disable=unbalanced-tuple-unpacking self.tag('c-format-string-error', prefix, tags.safestr(exc.message), flag, tags.safestr('in'), conv ) except backend.Error as exc: self.tag('c-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) if fmt is None: return for warn in fmt.warnings: try: raise warn except backend.RedundantFlag as exc: if len(exc.args) == 2: [s, *args] = exc.args else: [s, a1, a2] = exc.args # pylint: disable=unbalanced-tuple-unpacking if a1 == a2: args = ['duplicate', a1] else: args = [a1, tags.safe_format('overridden by {}', a2)] args += ['in', s] self.tag('c-format-string-redundant-flag', prefix, *args ) except backend.NonPortableConversion as exc: [s, c1, c2] = exc.args # pylint: disable=unbalanced-tuple-unpacking args = [c1, '=>', c2] if s != c1: args += ['in', s] self.tag('c-format-string-non-portable-conversion', prefix, *args ) return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): prefix = message_repr(message, template='{}:') src_args = src_fmt.arguments dst_args = dst_fmt.arguments if len(dst_args) > len(src_args): self.tag('c-format-string-excess-arguments', prefix, len(dst_args), tags.safestr(f'({dst_loc})'), '>', len(src_args), tags.safestr(f'({src_loc})'), ) elif len(dst_args) < len(src_args): if omitted_int_conv_ok: n_args_omitted = len(src_args) - len(dst_args) omitted_int_conv_ok = src_fmt.get_last_integer_conversion(n=n_args_omitted) if not omitted_int_conv_ok: self.tag('c-format-string-missing-arguments', prefix, len(dst_args), tags.safestr(f'({dst_loc})'), '<', len(src_args), tags.safestr(f'({src_loc})'), ) for src_arg, dst_arg in zip(src_args, dst_args): src_arg = src_arg[0] dst_arg = dst_arg[0] if src_arg.type != dst_arg.type: self.tag('c-format-string-argument-type-mismatch', prefix, tags.safestr(dst_arg.type), tags.safestr(f'({dst_loc})'), '!=', tags.safestr(src_arg.type), tags.safestr(f'({src_loc})'), ) __all__ = ['Checker'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/check/msgformat/perlbrace.py0000644000000000000000000000545714275257143022136 0ustar00rootroot00000000000000# Copyright © 2016-2020 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: Perl Locale::TextDomain ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import perlbrace as backend class Checker(CheckerBase): backend = backend # pylint: disable=self-assigning-variable def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.Error as exc: self.tag('perl-brace-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) else: return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): def sort_key(item): return (isinstance(item, str), item) prefix = message_repr(message, template='{}:') src_args = src_fmt.arguments dst_args = dst_fmt.arguments for key in sorted(dst_args - src_args, key=sort_key): self.tag('perl-brace-format-string-unknown-argument', prefix, key, tags.safestr('in'), tags.safestr(dst_loc), tags.safestr('but not in'), tags.safestr(src_loc), ) missing_keys = src_args - dst_args if len(missing_keys) == 1 and omitted_int_conv_ok: missing_keys = () for key in sorted(missing_keys): self.tag('perl-brace-format-string-missing-argument', prefix, key, tags.safestr('not in'), tags.safestr(dst_loc), tags.safestr('while in'), tags.safestr(src_loc), ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/check/msgformat/pybrace.py0000644000000000000000000000670614275257143021622 0ustar00rootroot00000000000000# Copyright © 2016-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: Python's str.format() ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import pybrace as backend class Checker(CheckerBase): backend = backend # pylint: disable=self-assigning-variable def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.Error as exc: self.tag('python-brace-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) else: return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): def sort_key(item): return (isinstance(item, str), item) prefix = message_repr(message, template='{}:') src_args = src_fmt.argument_map dst_args = dst_fmt.argument_map for key in sorted(dst_args.keys() & src_args.keys(), key=sort_key): src_arg = src_args[key][0] dst_arg = dst_args[key][0] if not (src_arg.types & dst_arg.types): self.tag('python-brace-format-string-argument-type-mismatch', prefix, tags.safestr(str.join(', ', dst_arg.types)), tags.safestr(f'({dst_loc})'), '!=', tags.safestr(str.join(', ', src_arg.types)), tags.safestr(f'({src_loc})'), ) for key in sorted(dst_args.keys() - src_args.keys(), key=sort_key): self.tag('python-brace-format-string-unknown-argument', prefix, key, tags.safestr('in'), tags.safestr(dst_loc), tags.safestr('but not in'), tags.safestr(src_loc), ) missing_keys = src_args.keys() - dst_args.keys() if len(missing_keys) == 1 and omitted_int_conv_ok: [missing_key] = missing_keys if all('int' in arg.types for arg in src_args[missing_key]): missing_keys = set() for key in sorted(missing_keys): self.tag('python-brace-format-string-missing-argument', prefix, key, tags.safestr('not in'), tags.safestr(dst_loc), tags.safestr('while in'), tags.safestr(src_loc), ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/check/msgformat/python.py0000644000000000000000000001515014275257143021507 0ustar00rootroot00000000000000# Copyright © 2015-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: Python's %-formatting ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import python as backend class Checker(CheckerBase): backend = backend # pylint: disable=self-assigning-variable def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.ArgumentTypeMismatch as exc: [s, key, types] = exc.args # pylint: disable=unbalanced-tuple-unpacking self.tag('python-format-string-error', prefix, tags.safestr(exc.message), tags.safestr(key), tags.safestr(str.join(', ', sorted(x for x in types))), ) except backend.Error as exc: self.tag('python-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) if fmt is None: return for warn in fmt.warnings: try: raise warn except backend.RedundantFlag as exc: if len(exc.args) == 2: [s, *args] = exc.args else: [s, a1, a2] = exc.args # pylint: disable=unbalanced-tuple-unpacking if a1 == a2: args = ['duplicate', a1] else: args = [a1, tags.safe_format('overridden by {}', a2)] args += ['in', s] self.tag('python-format-string-redundant-flag', prefix, *args ) except backend.RedundantPrecision as exc: [s, a] = exc.args # pylint: disable=unbalanced-tuple-unpacking self.tag('python-format-string-redundant-precision', prefix, a, 'in', s ) except backend.RedundantLength as exc: [s, a] = exc.args # pylint: disable=unbalanced-tuple-unpacking self.tag('python-format-string-redundant-length', prefix, a, 'in', s ) except backend.ObsoleteConversion as exc: [s, c1, c2] = exc.args # pylint: disable=unbalanced-tuple-unpacking args = [c1, '=>', c2] if s != c1: args += ['in', s] self.tag('python-format-string-obsolete-conversion', prefix, *args ) if ctx.is_template: if len(fmt.seq_conversions) > 1: self.tag('python-format-string-multiple-unnamed-arguments', message_repr(message) ) elif len(fmt.seq_conversions) == 1: arg_for_plural = ( message.msgid_plural is not None and fmt.seq_conversions[0].type == 'int' ) if arg_for_plural: self.tag('python-format-string-unnamed-plural-argument', message_repr(message) ) return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): prefix = message_repr(message, template='{}:') # unnamed arguments: src_args = src_fmt.seq_arguments dst_args = dst_fmt.seq_arguments if len(dst_args) != len(src_args): self.tag('python-format-string-argument-number-mismatch', prefix, len(dst_args), tags.safestr(f'({dst_loc})'), '!=', len(src_args), tags.safestr(f'({src_loc})'), ) for src_arg, dst_arg in zip(src_args, dst_args): if src_arg.type != dst_arg.type: self.tag('python-format-string-argument-type-mismatch', prefix, tags.safestr(dst_arg.type), tags.safestr(f'({dst_loc})'), '!=', tags.safestr(src_arg.type), tags.safestr(f'({src_loc})'), ) # named arguments: src_args = src_fmt.map_arguments dst_args = dst_fmt.map_arguments for key in sorted(dst_args.keys() & src_args.keys()): src_arg = src_args[key][0] dst_arg = dst_args[key][0] if src_arg.type != dst_arg.type: self.tag('python-format-string-argument-type-mismatch', prefix, tags.safestr(dst_arg.type), tags.safestr(f'({dst_loc})'), '!=', tags.safestr(src_arg.type), tags.safestr(f'({src_loc})'), ) for key in sorted(dst_args.keys() - src_args.keys()): self.tag('python-format-string-unknown-argument', prefix, key, tags.safestr('in'), tags.safestr(dst_loc), tags.safestr('but not in'), tags.safestr(src_loc), ) missing_keys = src_args.keys() - dst_args.keys() if len(missing_keys) == 1 and omitted_int_conv_ok: [missing_key] = missing_keys if all(arg.type == 'int' for arg in src_args[missing_key]): missing_keys = set() for key in sorted(missing_keys): self.tag('python-format-string-missing-argument', prefix, key, tags.safestr('not in'), tags.safestr(dst_loc), tags.safestr('while in'), tags.safestr(src_loc), ) __all__ = ['Checker'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/check/msgrepr.py0000644000000000000000000000303114275257143017641 0ustar00rootroot00000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string representation of messages ''' from lib import tags def message_repr(message, template='{}'): subtemplate = 'msgid {id}' kwargs = dict(id=message.msgid) if message.msgctxt is not None: subtemplate += ' msgctxt {ctxt}' kwargs.update(ctxt=message.msgctxt) template = template.format(subtemplate) return tags.safe_format(template, **kwargs) __all__ = ['message_repr'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/cli.py0000644000000000000000000002011214275257143015653 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' command-line interface ''' import argparse import concurrent.futures import functools import io import os import subprocess as ipc import sys import tempfile from lib import check from lib import ling from lib import misc from lib import paths as pathmod from lib import tags from lib import terminal __version__ = '0.27.1' def initialize_terminal(): if sys.stdout.isatty(): terminal.initialize() if sys.stdout.errors != 'strict': return sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding=sys.stdout.encoding, errors='backslashreplace', line_buffering=sys.stdout.line_buffering, ) class Checker(check.Checker): def tag(self, tagname, *extra): if tagname in self.options.ignore_tags: return try: tag = tags.get_tag(tagname) except KeyError: raise misc.DataIntegrityError( f'attempted to emit an unknown tag: {tagname!r}' ) s = tag.format(self.fake_path, *extra, color=True) print(s) def check_regular_file(filename, *, options): checker_instance = Checker(filename, options=options) checker_instance.check() def copy_options(options, **update): kwargs = vars(options) kwargs.update(update) return argparse.Namespace(**kwargs) class UnsupportedFileType(ValueError): pass def check_deb(filename, *, options): if filename.endswith('.deb'): binary = True elif filename.endswith('.dsc'): binary = False else: raise UnsupportedFileType ignore_tags = set(options.ignore_tags) ignore_tags.add('unknown-file-type') with tempfile.TemporaryDirectory(prefix='i18nspector.deb.') as tmpdir: if binary: ipc.check_call(['dpkg-deb', '-x', filename, tmpdir]) real_root = os.path.join(tmpdir, '') else: real_root = os.path.join(tmpdir, 's', '') ipc.check_call( ['dpkg-source', '--no-copy', '--no-check', '-x', filename, real_root], stdout=ipc.DEVNULL # dpkg-source would be noisy without this... ) options = copy_options(options, ignore_tags=ignore_tags, fake_root=(real_root, os.path.join(filename, '')) ) for root, dirs, files in os.walk(tmpdir): del dirs for path in files: path = os.path.join(root, path) if os.path.islink(path): continue if os.path.isfile(path): check_file(path, options=options) def check_file(path, *, options): if options.unpack_deb: try: return check_deb(path, options=options) except UnsupportedFileType: pass return check_regular_file(path, options=options) def check_file_s(path, *, options): ''' check_file() with captured stdout ''' orig_stdout = sys.stdout sys.stdout = io_stdout = io.StringIO() try: check_file(path, options=options) finally: sys.stdout = orig_stdout return io_stdout.getvalue() def check_all(paths, *, options): if (len(paths) <= 1) or (options.jobs <= 1): for path in paths: check_file(path, options=options) else: Executor = concurrent.futures.ProcessPoolExecutor with Executor(max_workers=options.jobs) as executor: check_file_opt = functools.partial(check_file_s, options=options) for s in executor.map(check_file_opt, paths): sys.stdout.write(s) def get_cpu_count(): try: sched_getaffinity = os.sched_getaffinity except AttributeError: return os.cpu_count() or 1 else: return len(sched_getaffinity(0)) def parse_jobs(s): if s == 'auto': return get_cpu_count() n = int(s) if n <= 0: raise ValueError return n parse_jobs.__name__ = 'jobs' class VersionAction(argparse.Action): def __init__(self, option_strings, dest=argparse.SUPPRESS): super().__init__( option_strings=option_strings, dest=dest, nargs=0, help='show version information and exit' ) @staticmethod def _get_rply_version(): rply = check.gettext.intexpr.rply try: return rply.__version__ except AttributeError: # __version__ is available only since rply 0.7.5: # https://github.com/alex/rply/pull/58 pass if sys.version_info >= (3, 8): import importlib.metadata # pylint: disable=import-outside-toplevel,import-error,no-name-in-module return importlib.metadata.version('rply') # pylint: disable=no-member try: import pkg_resources # pylint: disable=import-outside-toplevel [dist, *rest] = pkg_resources.require('rply') del rest except ImportError: # oh well... return assert dist.project_name == 'rply' return dist.version def __call__(self, parser, namespace, values, option_string=None): print(f'{parser.prog} {__version__}') print('+ Python {0}.{1}.{2}'.format(*sys.version_info)) # pylint: disable=consider-using-f-string print(f'+ polib {check.polib.__version__}') rply_version = self._get_rply_version() if rply_version is not None: print(f'+ rply {rply_version}') parser.exit() def main(): initialize_terminal() ap = argparse.ArgumentParser(description=__doc__) ap.add_argument('--version', action=VersionAction) ap.add_argument('-l', '--language', metavar='LANG', help='assume this language') ap.add_argument('--unpack-deb', action='store_true', help='allow unpacking Debian packages') ap.add_argument('-j', '--jobs', type=parse_jobs, metavar='N', default=None, help='use N processes') ap.add_argument('--parallel', type=int, metavar='N', default=None, help=argparse.SUPPRESS) # renamed as -j/--jobs in 0.25 ap.add_argument('--file-type', metavar='FILE-TYPE', help=argparse.SUPPRESS) ap.add_argument('--traceback', action='store_true', help=argparse.SUPPRESS) ap.add_argument('files', metavar='FILE', nargs='+') options = ap.parse_args() files = options.files del options.files pathmod.check() if options.language is not None: try: language = ling.parse_language(options.language) language.fix_codes() except ling.LanguageError: if options.traceback: raise ap.error('invalid language') language.remove_encoding() language.remove_nonlinguistic_modifier() options.language = language if options.jobs is None: if options.parallel is not None: options.jobs = options.parallel if options.jobs is None: options.jobs = 1 del options.parallel options.ignore_tags = set() options.fake_root = None Checker.patch_environment() check_all(files, options=options) __all__ = ['main'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/domains.py0000644000000000000000000000456614275257143016555 0ustar00rootroot00000000000000# Copyright © 2013-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' special-use domain names ''' # https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml import re _regexps = [ # RFC 1035, §3.5 : '.+[.]in-addr[.]arpa', # RFC 3596, §2.5 : '.+[.]ip6[.]arpa', # RFC 6761, §6 : '(.+[.])?test', '(.+[.])?localhost', '(.+[.])?invalid', '(.+[.])?example([.](com|net|org))?', # RFC 6762, §3 : '(.+[.])local', ] _regexps = str.join('|', _regexps) _is_special = re.compile(f'^({_regexps})$').match def is_special_domain(domain): domain = domain.lower() return _is_special(domain) def is_email_in_special_domain(email): _, domain = email.rsplit('@', 1) return is_special_domain(domain) def is_dotless_domain(domain): return '.' not in domain def is_email_in_dotless_domain(email): # Technically, e-mail addresses in dotless domains are not forbidden. # But in practice they are almost certainly mistakes. # See also: RFC 7085 _, domain = email.rsplit('@', 1) return is_dotless_domain(domain) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/encodings.py0000644000000000000000000001751614275257143017073 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' - encoding information registry - codecs for unusual encodings ''' import codecs import configparser import encodings.aliases as encoding_aliases import functools import itertools import os import unicodedata import sys from lib import iconv from lib import misc from lib import paths class EncodingLookupError(LookupError): def __init__(self, encoding): LookupError.__init__(self, 'unknown encoding: ' + encoding) def _not_implemented(*args, **kwargs): # no coverage del args, kwargs raise NotImplementedError def charmap_encoding(encoding): def encode(input, errors='strict'): return codecs.charmap_encode(input, errors, encoding_table) def decode(input, errors='strict'): return codecs.charmap_decode(input, errors, decoding_table) path = os.path.join(paths.datadir, 'charmaps', encoding.upper()) try: file = open(path, 'rb') # pylint: disable=consider-using-with except FileNotFoundError: raise EncodingLookupError(encoding) with file: decoding_table = file.read() decoding_table = decoding_table.decode('UTF-8') encoding_table = codecs.charmap_build(decoding_table) return codecs.CodecInfo( encode=encode, decode=decode, streamreader=_not_implemented, streamwriter=_not_implemented, incrementalencoder=_not_implemented, incrementaldecoder=_not_implemented, name=encoding, ) def iconv_encoding(encoding): def encode(input, errors='strict'): output = iconv.encode(input, encoding=encoding, errors=errors) return output, len(input) def decode(input, errors='strict'): output = iconv.decode(bytes(input), encoding=encoding, errors=errors) return output, len(input) return codecs.CodecInfo( encode=encode, decode=decode, streamreader=_not_implemented, streamwriter=_not_implemented, incrementalencoder=_not_implemented, incrementaldecoder=_not_implemented, name=encoding, ) _interesting_ascii_bytes = bytes(itertools.chain([ 0, # NUL 4, # EOT 7, # BEL 8, # BS 9, # HT 10, # LF 11, # VT 12, # FF 13, # CR 27, # ESC ], range(32, 127))) _interesting_ascii_str = _interesting_ascii_bytes.decode() def _read_encodings(): path = os.path.join(paths.datadir, 'encodings') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') e2c = {} c2e = {} for encoding, extra in cp['portable-encodings'].items(): e2c[encoding] = None if extra == '': pycodec = codecs.lookup(encoding) e2c[encoding] = pycodec c2e.setdefault(pycodec.name, encoding) elif extra == 'not-python': pass else: raise misc.DataIntegrityError extra_encodings = { key.lower() for key, value in cp['extra-encodings'].items() } return (e2c, c2e, extra_encodings) [_portable_encodings, _pycodec_to_encoding, _extra_encodings] = _read_encodings() _unmangle_encoding = {} if sys.version_info >= (3, 9): # Python >= 3.9 replaces hyphens with underscores: # https://bugs.python.org/issue39337 # We need to undo this damage. for _key in set(_portable_encodings) | set(_extra_encodings): assert _key not in _unmangle_encoding _unmangle_encoding[_key.replace('-', '_')] = _key _key = None del _key def _read_control_characters(): path = os.path.join(paths.datadir, 'control-characters') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') for section in cp.values(): if not section.name: continue misc.check_sorted(section) for code, name in section.items(): if len(code) != 2: raise misc.DataIntegrityError code = chr(int(code, 16)) if unicodedata.category(code) != 'Cc': raise misc.DataIntegrityError if name.upper() != name: raise misc.DataIntegrityError yield (code, name) _control_character_names = dict(_read_control_characters()) def get_portable_encodings(python=True): return ( encoding for encoding, codec in _portable_encodings.items() if (not python) or (codec is not None) ) def is_portable_encoding(encoding, python=True): encoding = encoding.lower() if encoding.startswith('iso_'): encoding = 'iso-' + encoding[4:] if python: return _portable_encodings.get(encoding, None) is not None else: return encoding in _portable_encodings def propose_portable_encoding(encoding, python=True): del python # never used; only encodings supported by Python are proposed try: pycodec = codecs.lookup(encoding) new_encoding = _pycodec_to_encoding[pycodec.name] except LookupError: return assert is_portable_encoding(new_encoding, python=True) return new_encoding.upper() def is_ascii_compatible_encoding(encoding, *, missing_ok=True): try: decoded_ascii_bytes = _interesting_ascii_bytes.decode(encoding) if isinstance(decoded_ascii_bytes, bytes): # may happen on PyPy for non-text encodings raise RuntimeError return decoded_ascii_bytes == _interesting_ascii_str except UnicodeDecodeError: return False except LookupError: pass except Exception: # no coverage; pylint: disable=broad-except pass if missing_ok: return False else: raise EncodingLookupError(encoding) def _codec_search_function(encoding): encoding = _unmangle_encoding.get(encoding, encoding) if _portable_encodings.get(encoding, False) is None: # portable according to gettext documentation # but not supported directly by Python pass elif encoding in _extra_encodings: # non-portable, but used by real-world software pass else: return try: return charmap_encoding(encoding) except EncodingLookupError: return iconv_encoding(encoding) @functools.lru_cache(maxsize=1) def install_extra_encodings(): codecs.register(_codec_search_function) for enc_name in _portable_encodings: if enc_name.startswith('iso-'): suffix = enc_name[4:].replace('-', '_') encoding_aliases.aliases.setdefault(suffix, 'iso' + suffix) def get_character_name(ch): try: return unicodedata.name(ch) except ValueError: if unicodedata.category(ch) == 'Cn': return 'non-character' name = _control_character_names.get(ch) if name is None: raise return 'control character ' + name # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/gettext.py0000644000000000000000000001416014275257143016576 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' gettext header support: - header field names registry - date parser - plural expressions parser - string formats registry ''' import configparser import datetime import os import re from lib import intexpr from lib import misc from lib import paths # ============= # header fields # ============= def _read_header_fields(): path = os.path.join(paths.datadir, 'header-fields') with open(path, 'rt', encoding='ASCII') as file: fields = [ s.rstrip() for s in file if s.rstrip() and not s.startswith('#') ] misc.check_sorted(fields) return frozenset(fields) header_fields = _read_header_fields() # ========================== # header and message parsing # ========================== is_valid_field_name = re.compile(r'^[\x21-\x39\x3B-\x7E]+$').match # https://tools.ietf.org/html/rfc5322#section-3.6.8 def parse_header(s): lines = s.split('\n') if lines[-1] == '': lines.pop() for line in lines: key, *values = line.split(':', 1) if values and is_valid_field_name(key): assert len(values) == 1 value = values[0].strip(' \t') yield {key: value} else: yield line search_for_conflict_marker = re.compile(r'^#-#-#-#-# .+ #-#-#-#-#$', re.MULTILINE).search # https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/msgl-cat.c?id=v0.18.3#n590 # https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia # ============ # plural forms # ============ class PluralFormsSyntaxError(Exception): pass class PluralExpressionSyntaxError(PluralFormsSyntaxError): pass def parse_plural_expression(s): parser = intexpr.Parser() try: return parser.parse(s) except intexpr.LexingError: raise PluralExpressionSyntaxError except intexpr.ParsingError: raise PluralExpressionSyntaxError _parse_plural_forms = re.compile(r'nplurals=([1-9][0-9]*);[ \t]*plural=([^;]+);?').search def parse_plural_forms(s, strict=True): match = _parse_plural_forms(s) if match is None: raise PluralFormsSyntaxError n = int(match.group(1), 10) expr = parse_plural_expression(match.group(2)) if strict: if match.start() != 0: raise PluralFormsSyntaxError if match.end() != len(s): raise PluralFormsSyntaxError return (n, expr) else: ljunk = s[:match.start()] rjunk = s[match.end():] return (n, expr, ljunk, rjunk) # ===== # Dates # ===== class DateSyntaxError(Exception): pass class BoilerplateDate(DateSyntaxError): pass def _read_timezones(): path = os.path.join(paths.datadir, 'timezones') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.optionxform = str cp.read(path, encoding='ASCII') return { abbrev: offsets.split() for abbrev, offsets in cp['timezones'].items() } _timezones = _read_timezones() _tz_re = str.join('|', (re.escape(tz) for tz in _timezones)) _parse_date = re.compile(r''' ^ ( [0-9]{4}-[0-9]{2}-[0-9]{2} ) # YYYY-MM-DD (?: \s+ | T ) ( [0-9]{2}:[0-9]{2} ) # hh:mm (?: : [0-9]{2} )? # ss \s* (?: (?: GMT | UTC )? ( [+-] [0-9]{2} ) :? ( [0-9]{2} ) # ZZzz | [+]? (''' + _tz_re + ''') ) ? $ ''', re.VERBOSE).match boilerplate_date = 'YEAR-MO-DA HO:MI+ZONE' _search_for_date_boilerplate = re.compile(r''' ^ YEAR - | - MO - | - DA \s | \s HO : | : MI (?:[+]|$) | [+] ZONE $ ''', re.VERBOSE).search def fix_date_format(s, *, tz_hint=None): s = s.strip() if _search_for_date_boilerplate(s): raise BoilerplateDate if tz_hint is not None: datetime.datetime.strptime(tz_hint, '%z') # just check syntax match = _parse_date(s) if match is None: raise DateSyntaxError (date, time, zhour, zminute, zabbr) = match.groups() if (zhour is not None) and (zminute is not None): zone = zhour + zminute elif zabbr is not None: try: [zone] = _timezones[zabbr] except ValueError: raise DateSyntaxError('ambiguous timezone abbreviation: ' + zabbr) elif tz_hint is not None: zone = tz_hint else: raise DateSyntaxError s = f'{date} {time}{zone}' assert len(s) == 21, f'len({s!r}) != 21' parse_date(s) # just check syntax return s def parse_date(s): try: return datetime.datetime.strptime(s, '%Y-%m-%d %H:%M%z') except ValueError as exc: raise DateSyntaxError(exc) epoch = datetime.datetime(1995, 7, 2, tzinfo=datetime.timezone.utc) # ============== # string formats # ============== def _read_string_formats(): path = os.path.join(paths.datadir, 'string-formats') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='ASCII') section = cp['formats'] misc.check_sorted(section) return { name: frozenset(examples.split()) for name, examples in section.items() } string_formats = _read_string_formats() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/iconv.py0000644000000000000000000002336314275257143016235 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string encoding and decoding using iconv(3), with a fallback to iconv(1) ''' import ctypes import errno import os import subprocess as ipc import re import sys default_encoding = sys.getdefaultencoding() _boring_iconv_stderr = re.compile('\nTry .+ for more information[.]$') _libc = ctypes.CDLL(None, use_errno=True) try: _iconv_open = _libc.iconv_open _iconv_close = _libc.iconv_close _iconv = _libc.iconv except AttributeError: _iconv = _iconv_open = _iconv_close = None else: _iconv_open.argtypes = [ctypes.c_char_p, ctypes.c_char_p] _iconv_open.restype = ctypes.c_void_p _iconv_close.argtypes = [ctypes.c_void_p] _iconv_close.restype = ctypes.c_int _iconv.argtypes = ( [ctypes.c_void_p] + [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_size_t)] * 2 ) _iconv.restype = ctypes.c_size_t def _popen(*args): def set_lc_all_c(): os.environ['LC_ALL'] = 'C' # no coverage return ipc.Popen(args, # pylint: disable=consider-using-with stdin=ipc.PIPE, stdout=ipc.PIPE, stderr=ipc.PIPE, preexec_fn=set_lc_all_c, ) def encode(input: str, encoding=default_encoding, errors='strict'): if not isinstance(input, str): raise TypeError(f'input must be str, not {type(input).__name__}') if not isinstance(encoding, str): raise TypeError(f'encoding must be str, not {type(encoding).__name__}') if not isinstance(errors, str): raise TypeError(f'errors must be str, not {type(errors).__name__}') if len(input) == 0: return b'' if errors != 'strict': raise NotImplementedError(f'error handler {errors!r} is not implemented') return _encode(input, encoding=encoding) def _encode_dl(input: str, *, encoding): uencoding = 'UTF-32LE' uwidth = 4 binput = bytes(input, encoding=uencoding) assert len(binput) == len(input) * uwidth cd = _iconv_open(bytes(encoding, 'ASCII'), bytes(uencoding, 'ASCII')) assert isinstance(cd, int) if cd == ctypes.c_void_p(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) try: c_input = ctypes.c_char_p(binput) output_len = len(input) while True: inbuf = ctypes.cast(c_input, ctypes.POINTER(ctypes.c_char)) inbytesleft = ctypes.c_size_t(len(binput)) assert inbytesleft.value == len(binput) # no overflow outbuf = ctypes.create_string_buffer(output_len) outbytesleft = ctypes.c_size_t(output_len) assert outbytesleft.value == output_len # no overflow rc = _iconv(cd, None, None, None, None) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) inbufptr = ctypes.pointer(ctypes.cast(inbuf, ctypes.POINTER(ctypes.c_char))) outbufptr = ctypes.pointer(ctypes.cast(outbuf, ctypes.POINTER(ctypes.c_char))) rc = _iconv(cd, inbufptr, ctypes.byref(inbytesleft), outbufptr, ctypes.byref(outbytesleft), ) if rc != ctypes.c_size_t(-1).value: rc = _iconv(cd, None, None, outbufptr, ctypes.byref(outbytesleft), ) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() if rc == errno.E2BIG: output_len *= 2 continue elif rc in {errno.EILSEQ, errno.EINVAL}: begin = len(input) - inbytesleft.value // uwidth raise UnicodeEncodeError( encoding, input, begin, begin + 1, os.strerror(errno.EILSEQ), ) raise OSError(rc, os.strerror(rc)) assert inbytesleft.value == 0, f'{inbytesleft.value} bytes left' output_len -= outbytesleft.value return outbuf[:output_len] finally: rc = _iconv_close(cd) if rc != 0: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) def _encode_cli(input, *, encoding): child = _popen('iconv', '-f', 'UTF-8', '-t', encoding) (stdout, stderr) = child.communicate(input.encode('UTF-8')) if stderr != b'': stderr = stderr.decode('ASCII', 'replace') stderr = _boring_iconv_stderr.sub('', stderr) raise UnicodeEncodeError(encoding, input, # .object 0, # .begin len(input), # .end stderr.strip() # .reason ) return stdout _encode = _encode_dl if _iconv is not None else _encode_cli def decode(input: bytes, encoding=default_encoding, errors='strict'): if not isinstance(input, bytes): raise TypeError(f'input must be bytes, not {type(input).__name__}') if not isinstance(encoding, str): raise TypeError(f'encoding must be str, not {type(encoding).__name__}') if not isinstance(errors, str): raise TypeError(f'errors must be str, not {type(errors).__name__}') if len(input) == 0: return '' if errors != 'strict': raise NotImplementedError(f'error handler {errors!r} is not implemented') return _decode(input, encoding=encoding) def _decode_dl(input: bytes, *, encoding): cd = _iconv_open(b'WCHAR_T', bytes(encoding, 'ASCII')) assert isinstance(cd, int) if cd == ctypes.c_void_p(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) try: c_input = ctypes.c_char_p(input) output_len = len(input) while True: inbuf = ctypes.cast(c_input, ctypes.POINTER(ctypes.c_char)) inbytesleft = ctypes.c_size_t(len(input)) assert inbytesleft.value == len(input) # no overflow outbuf = ctypes.create_unicode_buffer(output_len) outbytesleft = ctypes.c_size_t(output_len) # no overflow assert outbytesleft.value == output_len rc = _iconv(cd, None, None, None, None) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) inbufptr = ctypes.pointer(ctypes.cast(inbuf, ctypes.POINTER(ctypes.c_char))) outbufptr = ctypes.pointer(ctypes.cast(outbuf, ctypes.POINTER(ctypes.c_char))) rc = _iconv(cd, inbufptr, ctypes.byref(inbytesleft), outbufptr, ctypes.byref(outbytesleft), ) if rc != ctypes.c_size_t(-1).value: rc = _iconv(cd, None, None, outbufptr, ctypes.byref(outbytesleft), ) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() if rc == errno.E2BIG: output_len *= 2 continue elif rc in {errno.EILSEQ, errno.EINVAL}: begin = len(input) - inbytesleft.value for end in range(begin + 1, len(input)): # Assume that the encoding can be synchronized on ASCII characters. # That's not necessarily true for _every_ encoding, but oh well. if input[end] < 0x80: break else: end = len(input) raise UnicodeDecodeError( encoding, input, begin, end, os.strerror(errno.EILSEQ), ) raise OSError(rc, os.strerror(rc)) assert inbytesleft.value == 0, f'{inbytesleft.value} bytes left' output_len -= outbytesleft.value assert output_len % ctypes.sizeof(ctypes.c_wchar) == 0 unicode_output_len = output_len // ctypes.sizeof(ctypes.c_wchar) return outbuf[:unicode_output_len] finally: rc = _iconv_close(cd) if rc != 0: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) def _decode_cli(input, *, encoding): child = _popen('iconv', '-f', encoding, '-t', 'UTF-8') (stdout, stderr) = child.communicate(input) if stderr != b'': stderr = stderr.decode('ASCII', 'replace') stderr = _boring_iconv_stderr.sub('', stderr) raise UnicodeDecodeError(encoding, input, # .object 0, # .begin len(input), # .end stderr.strip() # .reason ) return stdout.decode('UTF-8') _decode = _decode_dl if _iconv is not None else _decode_cli __all__ = ['encode', 'decode'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/intexpr.py0000644000000000000000000004354514275257143016614 0ustar00rootroot00000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' C integer expressions ''' import ast import functools import types import rply import rply.errors LexingError = rply.errors.LexingError ParsingError = rply.errors.ParsingError # https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/plural.y?id=v0.18.3#n132 @functools.lru_cache(maxsize=None) def create_lexer(): lg = rply.LexerGenerator() lg.add('IF', r'[?]') lg.add('ELSE', r':') lg.add('OR', r'[|][|]') lg.add('AND', r'[&][&]') lg.add('EQ', r'[!=]=') lg.add('CMP', r'[<>]=?') lg.add('ADDSUB', r'[+-]') lg.add('MULDIV', r'[*/%]') lg.add('NOT', r'!') lg.add('LPAR', r'[(]') lg.add('RPAR', r'[)]') lg.add('VAR', r'n') lg.add('INT', r'[0-9]+') lg.ignore(r'[ \t]+') return lg.build() @functools.lru_cache(maxsize=None) def create_parser(lexer): pg = rply.ParserGenerator( [rule.name for rule in lexer.rules], precedence=[ ('right', ['IF', 'ELSE']), ('left', ['OR']), ('left', ['AND']), ('left', ['EQ']), ('left', ['CMP']), ('left', ['ADDSUB']), ('left', ['MULDIV']), ('right', ['NOT']), ], cache_id='i18nspector-intexpr', ) ast_bool = { '&&': ast.And(), '||': ast.Or(), } ast_cmp = { '==': ast.Eq(), '!=': ast.NotEq(), '<': ast.Lt(), '<=': ast.LtE(), '>': ast.Gt(), '>=': ast.GtE(), } ast_arithmetic = { '+': ast.Add(), '-': ast.Sub(), '*': ast.Mult(), '/': ast.Div(), '%': ast.Mod(), } ast_not = ast.Not() # pylint: disable=unused-variable @pg.production('start : exp') def eval_start(p): [exp] = p return ast.Expr(exp) @pg.production('exp : exp IF exp ELSE exp') def expr_ifelse(p): [cond, _, body, _, orelse] = p return ast.IfExp(cond, body, orelse) @pg.production('exp : exp OR exp') @pg.production('exp : exp AND exp') def expr_bool(p): [left, tok, right] = p op = ast_bool[tok.getstr()] return ast.BoolOp(op, [left, right]) @pg.production('exp : exp EQ exp') @pg.production('exp : exp CMP exp') def expr_cmp(p): [left, tok, right] = p op = ast_cmp[tok.getstr()] return ast.Compare(left, [op], [right]) @pg.production('exp : exp ADDSUB exp') @pg.production('exp : exp MULDIV exp') def expr_arithmetic(p): [left, tok, right] = p op = ast_arithmetic[tok.getstr()] return ast.BinOp(left, op, right) @pg.production('exp : NOT exp') def expr_not(p): [_, value] = p return ast.UnaryOp(ast_not, value) @pg.production('exp : LPAR exp RPAR') def expr_par(p): [_, exp, _] = p return exp @pg.production('exp : VAR') def expr_var(p): [tok] = p ident = tok.getstr() assert ident == 'n' return ast.Name(ident, ast.Load()) @pg.production('exp : INT') def expr_int(p): [tok] = p n = int(tok.getstr()) return ast.Num(n) # pylint: enable=unused-variable with misc.throwaway_tempdir('rply'): # Use private temporary directory # to mitigate RPLY's insecure use of /tmp: # CVE-2014-1604, CVE-2014-1938 return pg.build() class Parser(): def __init__(self): self._lexer = create_lexer() self._parser = create_parser(self._lexer) def parse(self, s): tokens = self._lexer.lex(s) node = self._parser.parse(tokens) return Expression(node) from lib import misc # pylint: disable=wrong-import-position class BaseEvaluator(): def __init__(self, node): self._ctxt = types.SimpleNamespace() self._node = node def __call__(self): node = self._node assert isinstance(node, ast.Expr) return self._visit_expr(node) def _visit(self, node, *args): try: fn = getattr(self, '_visit_' + type(node).__name__.lower()) except AttributeError: # no coverage raise NotImplementedError(type(node).__name__) return fn(node, *args) def _visit_expr(self, node): [node] = ast.iter_child_nodes(node) return self._visit(node) # binary operators # ================ def _visit_binop(self, node): x = self._visit(node.left) if x is None: return y = self._visit(node.right) if y is None: return return self._visit(node.op, x, y) # unary operators # =============== def _visit_unaryop(self, node): x = self._visit(node.operand) if x is None: return return self._visit(node.op, x) # comparison operators # ==================== def _visit_compare(self, node): assert len(node.comparators) == len(node.ops) if len(node.ops) != 1: raise NotImplementedError left = node.left [op] = node.ops [right] = node.comparators left = self._visit(left) if left is None: return right = self._visit(right) if right is None: return return self._visit(op, left, right) # boolean operators # ================= def _visit_boolop(self, node): return self._visit(node.op, *node.values) class Evaluator(BaseEvaluator): def __init__(self, node, n, *, bits): super().__init__(node) self._ctxt.n = n self._ctxt.max = 1 << bits def _check_overflow(self, n): if n < 0: raise OverflowError(n) if n >= self._ctxt.max: raise OverflowError(n) return n # pylint: disable=unused-argument # binary operators # ================ def _visit_add(self, node, x, y): return self._check_overflow(x + y) def _visit_sub(self, node, x, y): return self._check_overflow(x - y) def _visit_mult(self, node, x, y): return self._check_overflow(x * y) def _visit_div(self, node, x, y): return x // y def _visit_mod(self, node, x, y): return x % y # unary operators # =============== def _visit_not(self, node, x): return int(not x) # comparison operators # ==================== def _visit_gte(self, node, x, y): return int(x >= y) def _visit_gt(self, node, x, y): return int(x > y) def _visit_lte(self, node, x, y): return int(x <= y) def _visit_lt(self, node, x, y): return int(x < y) def _visit_eq(self, node, x, y): return int(x == y) def _visit_noteq(self, node, x, y): return int(x != y) # boolean operators # ================= def _visit_and(self, node, *args): for arg in args: if self._visit(arg) == 0: return 0 return 1 def _visit_or(self, node, *args): for arg in args: if self._visit(arg) != 0: return 1 return 0 # if-then-else expression # ======================= def _visit_ifexp(self, node): test = self._visit(node.test) if test: return self._visit(node.body) else: return self._visit(node.orelse) # constants, variables # ==================== def _visit_num(self, node): return self._check_overflow(node.n) _visit_constant = _visit_num def _visit_name(self, node): return self._check_overflow(self._ctxt.n) # pylint: enable=unused-argument class CodomainEvaluator(BaseEvaluator): def __init__(self, node, *, bits): super().__init__(node) self._ctxt.max = 1 << bits # pylint: disable=unused-argument # binary operators # ================ def _visit_add(self, node, x, y): z = ( x[0] + y[0], min(x[1] + y[1], self._ctxt.max - 1) ) if z[0] > z[1]: return return z def _visit_sub(self, node, x, y): z = ( max(x[0] - y[1], 0), x[1] - y[0] ) if z[0] > z[1]: return return z def _visit_mult(self, node, x, y): z = ( x[0] * y[0], min(x[1] * y[1], self._ctxt.max - 1) ) if z[0] > z[1]: return return z def _visit_div(self, node, x, y): if y == (0, 0): # division by zero return assert y[1] > 0 return ( x[0] // y[1], x[1] // max(y[0], 1), ) def _visit_mod(self, node, x, y): if y == (0, 0): # division by zero return assert y[1] > 0 if x[1] < y[0]: # i % j == i if i < j return x return (0, min(x[1], y[1] - 1)) # unary operators # =============== def _visit_not(self, node, x): if x[0] > 0: return (0, 0) elif x == (0, 0): return (1, 1) else: return (0, 1) # comparison operators # ==================== def _visit_gte(self, node, x, y): assert (x is not None) and (y is not None) return ( x[0] >= y[1], x[1] >= y[0], ) def _visit_gt(self, node, x, y): assert (x is not None) and (y is not None) return ( x[0] > y[1], x[1] > y[0], ) def _visit_lte(self, node, x, y): assert (x is not None) and (y is not None) return ( x[1] <= y[0], x[0] <= y[1], ) def _visit_lt(self, node, x, y): assert (x is not None) and (y is not None) return ( x[1] < y[0], x[0] < y[1], ) def _visit_eq(self, node, x, y): assert (x is not None) and (y is not None) if x[0] == x[1] == y[0] == y[1]: return (1, 1) if x[0] <= y[0] <= x[1]: return (0, 1) if y[0] <= x[0] <= y[1]: return (0, 1) return (0, 0) def _visit_noteq(self, node, x, y): assert (x is not None) and (y is not None) if x[0] == x[1] == y[0] == y[1]: return (0, 0) if x[0] <= y[0] <= x[1]: return (0, 1) if y[0] <= x[0] <= y[1]: return (0, 1) return (1, 1) # boolean operators # ================= def _visit_and(self, node, *args): r = (1, 1) for arg in args: assert r != (0, 0) x = self._visit(arg) if x is None: if r == (0, 1): return (0, 0) else: return elif x == (0, 0): return x elif x[0] >= 1: pass else: assert (x[0] == 0) and (x[1] > 0) r = (0, 1) return r def _visit_or(self, node, *args): r = (0, 0) for arg in args: assert r != (1, 1) x = self._visit(arg) if x is None: if r == (0, 1): return (1, 1) else: return elif x[0] >= 1: return (1, 1) elif x == (0, 0): pass else: assert (x[0] == 0) and (x[1] > 0) r = (0, 1) return r # if-then-else expression # ======================= def _visit_ifexp(self, node): test = self._visit(node.test) if test is None: return x = y = None if test[1] > 0: x = self._visit(node.body) if test[0] == 0: y = self._visit(node.orelse) if x is None: return y if y is None: return x return ( min(x[0], y[0]), max(x[1], y[1]), ) # constants, variables # ==================== def _visit_num(self, node): n = node.n if (n < 0) or (n >= self._ctxt.max): return return (n, n) _visit_constant = _visit_num def _visit_name(self, node): return (0, self._ctxt.max - 1) # pylint: enable=unused-argument def gcd(x, y): while y: (x, y) = (y, x % y) return x def lcm(x, *ys): r = x for y in ys: r //= gcd(r, y) r *= y return r class PeriodEvaluator(BaseEvaluator): def __init__(self, node, *, bits): super().__init__(node) self._ctxt.max = 1 << bits # binary operators # ================ def _visit_binop(self, node): const_mod = ( isinstance(node.op, ast.Mod) and isinstance(node.left, ast.Name) and isinstance(node.right, ast.Num) ) if const_mod: n = node.right.n if (n <= 0) or (n >= self._ctxt.max): return return (0, n) x = self._visit(node.left) if x is None: return y = self._visit(node.right) if y is None: return (xo, xp) = x (yo, yp) = y ro = max(xo, yo) rp = lcm(xp, yp) if rp >= self._ctxt.max: return else: return (ro, rp) # unary operators # =============== def _visit_unaryop(self, node): return self._visit(node.operand) # comparison operators # ==================== def _visit_compare(self, node): assert len(node.comparators) == len(node.ops) if len(node.ops) != 1: raise NotImplementedError [op] = node.ops [right] = node.comparators const_cmp = ( isinstance(node.left, ast.Name) and isinstance(right, ast.Num) ) if const_cmp: n = right.n if (n < 0) or (n >= self._ctxt.max): return # (n N) is constant starting with either N or N+1, # depending on : # # …N-1 N N+1 N+2… # -------+---+---+---+---- # n != N | 1 . 0 . 1 . 1 # n == N | 0 . 1 . 0 . 0 # n <= N | 1 . 1 . 0 . 0 # n > N | 0 . 0 . 1 . 1 # -------+---+---+---+---- # n < N | 1 . 0 . 0 . 0 # n >= N | 0 . 1 . 1 . 1 # -------+---+---+---+---- if isinstance(op, (ast.Lt, ast.GtE)): return (n, 1) else: if n + 1 == self._ctxt.max: return return (n + 1, 1) x = self._visit(node.left) if x is None: return y = self._visit(right) if y is None: return (xo, xp) = x (yo, yp) = y ro = max(xo, yo) rp = lcm(xp, yp) if rp >= self._ctxt.max: return else: return (ro, rp) # boolean operators # ================= def _visit_boolop(self, node): (xo, xp) = (0, 1) for arg in node.values: y = self._visit(arg) if y is None: return (yo, yp) = y xo = max(xo, yo) xp = lcm(xp, yp) if xp >= self._ctxt.max: return return (xo, xp) # if-then-else expression # ======================= def _visit_ifexp(self, node): test = self._visit(node.test) if test is None: return (to, tp) = test x = self._visit(node.body) if x is None: return (xo, xp) = x y = self._visit(node.orelse) if y is None: return (yo, yp) = y ro = max(to, xo, yo) rp = lcm(tp, xp, yp) if rp >= self._ctxt.max: return else: return (ro, rp) # constants, variables # ==================== def _visit_num(self, node): n = node.n if n < 0 or n >= self._ctxt.max: return return (0, 1) _visit_constant = _visit_num def _visit_name(self, node): # pylint: disable=unused-argument pass class Expression(): def __init__(self, node): if not isinstance(node, ast.Expr): raise TypeError # no coverage self._node = node def __call__(self, n, *, bits=32): ''' return f(n) ''' e = Evaluator(self._node, n, bits=bits) return e() def codomain(self, *, bits=32): ''' return * (L, R) such that for every n: L ≤ f(n) ≤ R * or None ''' e = CodomainEvaluator(self._node, bits=bits) return e() def period(self, *, bits=32): ''' return * (O, P) such that for every n ≥ O: f(n + P) = f(n) * or None ''' e = PeriodEvaluator(self._node, bits=bits) return e() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/ling.py0000644000000000000000000002635114275257143016050 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' language information registry ''' import configparser import os import re import unicodedata from lib import misc from lib import paths def _munch_language_name(s): # Normalize whitespace: s = str.join(' ', s.split()) # Normalize capitalization: s = s.lower() # Strip accent marks etc.: s = unicodedata.normalize('NFD', s).encode('ASCII', 'ignore').decode() return s class LanguageError(ValueError): pass class LanguageSyntaxError(LanguageError): pass class FixingLanguageCodesFailed(LanguageError): pass class FixingLanguageEncodingFailed(LanguageError): pass class Language(): def __init__(self, language_code, territory_code=None, encoding=None, modifier=None): self.language_code = language_code if language_code is None: raise TypeError('language_code must not be None') # no coverage self.territory_code = territory_code self.encoding = None if encoding is not None: self.encoding = encoding.upper() self.modifier = modifier def _get_tuple(self): return ( self.language_code, self.territory_code, self.encoding, self.modifier ) def clone(self): return Language(*self._get_tuple()) def __eq__(self, other): if not isinstance(other, Language): return NotImplemented return self._get_tuple() == other._get_tuple() # pylint: disable=protected-access def __ne__(self, other): return not self == other def is_almost_equal(self, other): if not isinstance(other, Language): raise TypeError self_clone = self.clone() self_clone.remove_principal_territory_code() other_clone = other.clone() other_clone.remove_principal_territory_code() return self_clone == other_clone def fix_codes(self): fixed = None ll = self.language_code ll = _lookup_language_code(ll) if ll is None: # TODO: Try to guess correct language code. raise FixingLanguageCodesFailed() elif ll != self.language_code: fixed = True cc = self.territory_code if cc is not None: cc = lookup_territory_code(cc) if cc is None: # TODO: Try to guess correct territory code. raise FixingLanguageCodesFailed() elif cc != self.territory_code: # This shouldn't really happen, but better safe than sorry. raise ValueError # no coverage # TODO: ll_CC could be still incorrect, even when both ll and CC are # correct. self.language_code = ll self.territory_code = cc return fixed def get_principal_territory_code(self): ll = self.language_code assert ll is not None return _get_principal_territory_code(ll) def remove_principal_territory_code(self): cc = self.territory_code if cc is None: return default_cc = self.get_principal_territory_code() if cc == default_cc: self.territory_code = None return True def remove_encoding(self): if self.encoding is None: return self.encoding = None return True def remove_nonlinguistic_modifier(self): if self.modifier == 'euro': self.modifier = None return True return def get_plural_forms(self): result = None if self.territory_code is not None: code = self._simple_format() result = _get_plural_forms(code) if result is None: code = self._simple_format(territory=False) result = _get_plural_forms(code) return result def get_unrepresentable_characters(self, encoding, strict=False): characters = None if self.territory_code is not None: code = self._simple_format() characters = _get_characters(code, self.modifier, strict=strict) if characters is None: code = self._simple_format(territory=False) characters = _get_characters(code, self.modifier, strict=strict) if characters is None: return result = [] try: # If iconv(1) is used to implement an encoding, there's a huge # overhead per encode() call. To reduce number of such calls, # optimize the common case of all characters being representable. str.join('', characters).encode(encoding) except UnicodeEncodeError: pass else: return result for character in characters: try: character.encode(encoding) except UnicodeEncodeError as exc: result += [character] if exc.reason.startswith('iconv:'): # pylint: disable=no-member # Avoid further calls to iconv(1): break return result def _simple_format(self, territory=True): s = self.language_code if territory and self.territory_code is not None: s += '_' + self.territory_code return s def __str__(self): s = self.language_code if self.territory_code is not None: s += '_' + self.territory_code if self.encoding is not None: s += '.' + self.encoding if self.modifier is not None: s += '@' + self.modifier return s def __repr__(self): return f'' def _read_iso_codes(): # ISO language/territory codes: path = os.path.join(paths.datadir, 'iso-codes') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') cfg_iso_639 = cp['language-codes'] misc.check_sorted(cfg_iso_639) iso_639 = {} for lll, ll in cfg_iso_639.items(): if ll: iso_639[ll] = ll iso_639[lll] = ll else: iso_639[lll] = lll cfg_iso_3166 = cp['territory-codes'] misc.check_sorted(cfg_iso_3166) iso_3166 = frozenset(cc.upper() for cc in cfg_iso_3166.keys()) return (iso_639, iso_3166) [_iso_639, _iso_3166] = _read_iso_codes() def _read_primary_languages(): # Hand-edited linguistic data: path = os.path.join(paths.datadir, 'languages') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') primary_languages = {name: sect for name, sect in cp.items() if sect.name} name_to_code = {} misc.check_sorted(cp) for language, section in cp.items(): if not language: continue for key in section.keys(): if key in {'names', 'characters', 'macrolanguage', 'plural-forms', 'principal-territory'}: continue if key.startswith('characters@'): continue raise misc.DataIntegrityError(f'unknown key: {key}') for name in section['names'].splitlines(): name = _munch_language_name(name) if name: if name in name_to_code: raise misc.DataIntegrityError name_to_code[name] = language return primary_languages, name_to_code def _check_primary_languages_coverage(): # Check if primary languages have full ISO 639-1 coverage: for ll in _iso_639: if len(ll) > 2: continue try: _primary_languages[ll] except LookupError: # no coverage raise misc.DataIntegrityError [_primary_languages, _name_to_code] = _read_primary_languages() _check_primary_languages_coverage() def _lookup_language_code(language): return _iso_639.get(language) def lookup_territory_code(cc): if cc in _iso_3166: return cc def get_language_for_name(name): parse = parse_language _name = _munch_language_name(name) try: return parse(_name_to_code[_name]) except KeyError: pass if ';' in _name: for subname in _name.split(';'): subname = subname.strip() try: return parse(_name_to_code[subname]) except LookupError: pass if ',' in _name: subname = str.join(' ', map(str.strip, _name.split(',', 1)[::-1])) try: return parse(_name_to_code[subname]) except LookupError: pass results = set() for subname in _name.split(','): subname = subname.strip() result = _name_to_code.get(subname) if result is not None: results.add(result) if len(results) == 1: return parse(results.pop()) raise LookupError(name) _language_regexp = re.compile(r''' ^ ( [a-z]{2,} ) (?: _ ( [A-Z]{2,} ) )? (?: [.] ( [a-zA-Z0-9+-]+ ) )? (?: @ ( [a-z]+) )? $''', re.VERBOSE) def parse_language(s): match = _language_regexp.match(s) if match is None: raise LanguageSyntaxError return Language(*match.groups()) def get_primary_languages(): return iter(_primary_languages) def _get_plural_forms(language): try: section = _primary_languages[language] except KeyError: return plural_forms = section.get('plural-forms') if plural_forms is None: return return [ s.strip() for s in plural_forms.splitlines() if s and not s.isspace() ] def _get_principal_territory_code(language): try: section = _primary_languages[language] except KeyError: return return section.get('principal-territory') def _get_characters(language, modifier=None, strict=True): try: section = _primary_languages[language] except KeyError: return section_name = 'characters' if modifier is not None: section_name += f'@{modifier}' result = section.get(section_name) if result is None: return if strict: return [ ch.strip('()') for ch in result.split() ] else: return [ ch for ch in result.split() if not (ch.startswith('(') and ch.endswith(')')) ] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/misc.py0000644000000000000000000000543114275257143016046 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' miscellanea ''' import contextlib import datetime import tempfile def unsorted(iterable): ''' if the iterable is sorted, return None; otherwise return first (x, y) such that x > y ''' iterable = iter(iterable) for x in iterable: break for y in iterable: if x > y: # pylint: disable=undefined-loop-variable return (x, y) # pylint: disable=undefined-loop-variable x = y class DataIntegrityError(Exception): pass def check_sorted(iterable, exception=DataIntegrityError): ''' raise exception if the iterable is not sorted ''' cx = unsorted(iterable) if cx is not None: raise exception(f'{cx[0]!r} > {cx[1]!r}') def sorted_vk(d): ''' iterate over d.values() in the key order ''' for k, v in sorted(d.items()): del k yield v def utc_now(): ''' timezone-aware variant of datetime.now() ''' return datetime.datetime.now( datetime.timezone.utc ) def format_range(rng, *, max): # pylint: disable=redefined-builtin last = rng[-1] result = [] if max < 4: raise ValueError('max must be >= 4') for i in rng: if len(result) < max: result += [i] else: result[-2:] = ['...', str(last)] break return str.join(', ', map(str, result)) @contextlib.contextmanager def throwaway_tempdir(context): with tempfile.TemporaryDirectory(prefix=f'i18nspector.{context}.') as new_tempdir: original_tempdir = tempfile.tempdir try: tempfile.tempdir = new_tempdir yield finally: tempfile.tempdir = original_tempdir # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/moparser.py0000644000000000000000000001671214275257143016747 0ustar00rootroot00000000000000# Copyright © 2013-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' MO file parser ''' # MO file format documentation: # * https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/gmo.h?id=v0.18.3 # * https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/read-mo.c?id=v0.18.3 # * https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html import re import struct import polib from lib import encodings little_endian_magic = b'\xDE\x12\x04\x95' big_endian_magic = little_endian_magic[::-1] class SyntaxError(Exception): # pylint: disable=redefined-builtin pass class Parser(): def __init__(self, path, *, encoding=None, check_for_duplicates=False, klass=None): self._encoding = encoding if check_for_duplicates: raise NotImplementedError with open(path, 'rb') as file: contents = file.read() view = memoryview(contents) view = view.cast('c') if len(view) > 0: assert isinstance(view[0], bytes) self._view = view if klass is None: klass = polib.MOFile try: self.instance = klass( fpath=path, check_for_duplicates=False, ) self._parse() finally: del self._view def parse(self): return self.instance def _read_ints(self, at, n=1): begin = at end = at + 4 * n view = self._view if end > len(view): raise SyntaxError('truncated file') return struct.unpack( self._endian + 'I' * n, view[begin:end], ) def _parse(self): view = self._view magic = view[:4].tobytes() if magic == little_endian_magic: self._endian = '<' elif magic == big_endian_magic: self._endian = '>' else: raise SyntaxError('unexpected magic') [revision] = self._read_ints(at=4) major_revision, minor_revision = divmod(revision, 1 << 16) if major_revision > 1: raise SyntaxError(f'unexpected major revision number: {major_revision}') [n_strings] = self._read_ints(at=8) possible_hidden_strings = False if minor_revision > 1: # “an unexpected minor revision number means that the file can be # read but will not reveal its full contents” possible_hidden_strings = True elif minor_revision == 1: [n_sysdep_strings] = self._read_ints(at=36) if n_sysdep_strings > 0: possible_hidden_strings = True self.instance.possible_hidden_strings = possible_hidden_strings [msgid_offset, msgstr_offset] = self._read_ints(at=12, n=2) self._last_msgid = None for i in range(n_strings): entry = self._parse_entry(i, msgid_offset + 8 * i, msgstr_offset + 8 * i) self.instance.append(entry) def _parse_entry(self, i, msgid_offset, msgstr_offset): view = self._view [length, offset] = self._read_ints(at=msgid_offset, n=2) msgid = view[offset:offset+length].tobytes() try: if view[offset + length] != b'\0': raise SyntaxError('msgid is not null-terminated') except IndexError: raise SyntaxError('truncated file') msgids = msgid.split(b'\0', 2) msgid = msgids[0] if len(msgids) > 2: raise SyntaxError('unexpected null byte in msgid') [length, offset] = self._read_ints(at=msgstr_offset, n=2) msgstr = view[offset:offset+length].tobytes() try: if view[offset + length] != b'\0': raise SyntaxError('msgstr is not null-terminated') except IndexError: raise SyntaxError('truncated file') msgstrs = msgstr.split(b'\0') if len(msgids) == 1 and len(msgstrs) > 1: raise SyntaxError('unexpected null byte in msgstr') encoding = self._encoding if i == 0: if encoding is None and msgid == b'': # https://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/dcigettext.c?id=v0.18.3#n1106 match = re.search(b'charset=([^ \t\n]+)', msgstr) if match is not None: try: encoding = match.group(1).decode('ASCII') except UnicodeError: pass if encoding is None: encoding = 'ASCII' elif not encodings.is_ascii_compatible_encoding(encoding): encoding = 'ASCII' self._encoding = encoding elif msgids == self._last_msgid: raise SyntaxError('duplicate message definition') elif msgid < self._last_msgid: raise SyntaxError('messages are not sorted') self._last_msgid = msgid # pylint: disable=attribute-defined-outside-init assert encoding is not None msgid, *msgctxt = msgid.split(b'\x04', 1) kwargs = dict(msgid=msgid.decode(encoding)) if msgctxt: [msgctxt] = msgctxt kwargs.update(msgctxt=msgctxt.decode(encoding)) if len(msgids) == 1: assert [msgstr] == msgstrs kwargs.update(msgstr=msgstr.decode(encoding)) else: assert len(msgids) == 2 assert len(msgstrs) >= 1 kwargs.update(msgid_plural=msgids[1].decode(encoding)) kwargs.update(msgstr_plural= {i: s.decode(encoding) for i, s in enumerate(msgstrs)} ) entry = polib.MOEntry(**kwargs) entry.comment = None entry.occurrences = () entry.flags = () # https://bitbucket.org/izi/polib/issues/47 entry.translated = lambda: True entry.previous_msgctxt = None entry.previous_msgid = None entry.previous_msgid_plural = None return entry __all__ = ['Parser', 'SyntaxError'] def main(): import argparse # pylint: disable=import-outside-toplevel ap = argparse.ArgumentParser(description='msgunfmt(1) replacement') ap.add_argument('files', metavar='FILE', nargs='+') options = ap.parse_args() for path in options.files: escaped_path = ascii(path)[1:-1] print('# ' + escaped_path, end='\n\n') parser = Parser(path) for entry in parser.parse(): print(entry) if __name__ == '__main__': main() else: del main # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/paths.py0000644000000000000000000000255414275257143016235 0ustar00rootroot00000000000000# Copyright © 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' paths to code and data ''' import os basedir = os.path.normpath(os.path.join( os.path.dirname(__file__), os.path.pardir, '', )) datadir = os.path.join(basedir, 'data', '') def check(): os.stat(basedir) os.stat(datadir) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/polib4us.py0000644000000000000000000001647314275257143016664 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' polib monkey-patching ''' import ast import codecs import inspect import re import polib from lib import encodings from lib import moparser # pylint: disable=protected-access patches = [] def install_patches(): for patch in patches: patch() __all__ = ['install_patches'] def register_patch(patch): patches.append(patch) # polib.default_encoding # ====================== # Do not allow broken/missing encoding declarations, unless the file is # ASCII-only. @register_patch def default_encoding_patch(): polib.default_encoding = 'ASCII' # polib.codecs # ============ # Work around a few PO parsing bugs: # - newline decoding: https://bugs.debian.org/692283 # - trailing comment parsing: https://bitbucket.org/izi/polib/issues/51 # - atypical comment parsing # - parsing of empty files: https://bitbucket.org/izi/polib/issues/59 class Codecs(): _iterlines = re.compile(r'[^\n]*(?:\n|\Z)').findall _atypical_comment = re.compile(r'#[^ .:,|~]').match def __getattr__(self, attr): return getattr(codecs, attr) def open(self, path, mode, encoding): if mode not in {'rU', 'rt'}: raise NotImplementedError if not encodings.is_ascii_compatible_encoding(encoding): encoding = 'ASCII' with open(path, 'rb') as file: contents = file.read() contents = contents.decode(encoding) pending_comments = [] empty = True for line in self._iterlines(contents): if self._atypical_comment(line): line = '# ' + line[1:] if line[:2] in {'', '# '} or line.isspace(): pending_comments += [line] else: yield from pending_comments pending_comments = [] yield line empty = False if empty: yield '# ' @register_patch def codecs_patch(): polib.codecs = polib.io = Codecs() # polib.POFile.find() # =================== # Make POFile.find() always return None. # That way the parser won't find the header entry, allowing us to parse it # ourselves. @register_patch def pofile_find_patch(): def pofile_find(self, *args, **kwargs): del self, args, kwargs polib.POFile.find = pofile_find # polib.unescape() # ================ # Work around an escape sequence decoding bug. # https://bitbucket.org/izi/polib/issues/31 _escapes_re = re.compile(r''' ( \\ (?: [ntbrfva] | \\ | " | [0-9]{1,3} | x[0-9a-fA-F]{1,2} ))+ ''', re.VERBOSE) _short_x_escape_re = re.compile(r''' \\x ([0-9a-fA-F]) (?= \\ | $ ) ''', re.VERBOSE) def polib_unescape(s): def unescape(match): s = match.group() s = _short_x_escape_re.sub(r'\\x0\1', s) result = ast.literal_eval(f"b'{s}'") try: return result.decode('ASCII') # pylint: disable=no-member except UnicodeDecodeError: # an ugly hack to discover encoding of the PO file: parser_stack_frame = inspect.stack()[2][0] parser = parser_stack_frame.f_locals['self'] encoding = parser.instance.encoding return result.decode(encoding) # pylint: disable=no-member return _escapes_re.sub(unescape, s) @register_patch def unescape_patch(): polib.unescape = polib_unescape # polib._MOFileParser # =================== # Use a custom MO file parser implementation. # https://bitbucket.org/izi/polib/issues/36 # https://bitbucket.org/izi/polib/issues/44 # https://bitbucket.org/izi/polib/issues/45 # https://bitbucket.org/izi/polib/issues/47 @register_patch def mo_parser_patch(): polib._MOFileParser = moparser.Parser # polib.detect_encoding() # ======================= # Don't use polib's detect_encoding() for MO files, as i18nspector's own MO # file parser has built-in encoding detection. @register_patch def detect_encoding_patch(): def detect_encoding(path, binary_mode=False): if binary_mode: return return original(path) original = polib.detect_encoding polib.detect_encoding = detect_encoding # polib.POEntry.flags # =================== # Fix flag splitting. # polib (<< 1.0.4) incorrectly requires that the flag-splitting comma must be # followed by a space. # https://bitbucket.org/izi/polib/issues/46 @register_patch def poentry_flags_patch(): def get_flags(self): return self._i18nspector_flags def set_flags(self, flags): self._i18nspector_flags = [ flag.strip(' \t\r\f\v') for subflags in flags for flag in subflags.split(',') ] polib.POEntry.flags = property(get_flags, set_flags) # polib.POEntry.msgstr_plural # =========================== # Force msgstr_plural keys to be integers. # polib (<< 1.0.4) uses strings there instead. # https://bitbucket.org/izi/polib/issues/49 class IntDict(dict): def __setitem__(self, key, value): super().__setitem__(int(key), value) def __getitem__(self, key): return super().__getitem__(int(key)) @register_patch def poentry_msgstr_plural_patch(): def get_msgstr_plural(self): return self._i18nspector_msgstr_plural def set_msgstr_plural(self, d): self._i18nspector_msgstr_plural = IntDict(d) polib.POEntry.msgstr_plural = property( get_msgstr_plural, set_msgstr_plural, ) # polib._BaseEntry.__init__() # =========================== # Distinguish between empty and non-existent msgid_plural. # Distinguish between empty and non-existent msgstr. @register_patch def base_entry_init_patch(): def init(self, *args, **kwargs): original(self, *args, **kwargs) if 'msgid_plural' not in kwargs: self.msgid_plural = None if 'msgstr' not in kwargs: self.msgstr = None original = polib._BaseEntry.__init__ polib._BaseEntry.__init__ = init # polib.POEntry.translated() # ========================== # Consider the message translated if any msgstr[N] is non-empty. @register_patch def poentry_translated_patch(): def translated(self): if self.obsolete: return False if 'fuzzy' in self.flags: return False return ( self.msgstr or any(self.msgstr_plural.values()) ) polib.POEntry.translated = translated # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/strformat/0000755000000000000000000000000014275257143016557 5ustar00rootroot00000000000000i18nspector-0.27.1/lib/strformat/__init__.py0000644000000000000000000000000014275257143020656 0ustar00rootroot00000000000000i18nspector-0.27.1/lib/strformat/c.py0000644000000000000000000003754314275257143017367 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string format checks: C ''' import collections import re _directive_re = re.compile(''' (?P [^%]+ ) | ( % (?P [0-9]+[$] )? (?P [#0 +'I-]* ) (?: (?P [1-9][0-9]* ) | (?P [*] ) (?P [0-9]+[$] )? )? (?: [.] (?: (?P [0-9]* ) | (?P [*] ) (?P [0-9]+[$] )? ) )? (?: (?P hh? | ll? | [qjzZt] | L )? (?P [diouxXeEfFgGaAcsCSpnm%] ) | < (?: PRI (?P[diouxX]) (?P (?:LEAST|FAST)?(?:8|16|32|64)|MAX|PTR) ) > ) ) ''', re.VERBOSE) def _printable_prefix(s, r=re.compile('[ -\x7E]+')): return r.match(s).group() class _info: oct_cvt = 'o' hex_cvt = 'xXaA' dec_cvt = 'diufFgG' float_cvt = 'aAeEfFgG' uint_cvt = 'ouxX' int_cvt = 'di' + uint_cvt str_cvt = 'sS' int_types = ''' hh = signed char | unsigned char h = short int | unsigned short int l = long int | unsigned long int ll = long long int | unsigned long long int j = intmax_t | uintmax_t z = ssize_t | size_t t = ptrdiff_t | [unsigned ptrdiff_t] = int | unsigned int ''' int_types = { key: tuple(str.strip(v) for v in values.split('|')) for line in int_types.strip().splitlines() for key, values in [map(str.strip, line.split('='))] } # FIXME: The printf(3) manpage says that the type for signed integer with # “z“ size is ssize_t. # But SUSv3 says it's a signed integer type corresponding to size_t, # which is not necessarily the same thing as ssize_t. # https://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html portable_int_lengths = dict( L='ll', q='ll', Z='z', ) INT_MAX = (1 << 31) - 1 # on most architectures NL_ARGMAX = 4096 # on GNU/Linux class Error(Exception): message = 'invalid conversion specification' class NonPortableConversion(Error): message = 'non-portable conversion specifier or length modifier' # errors in argument indexing: class ForbiddenArgumentIndex(Error): message = 'argument index not allowed' class ArgumentRangeError(Error): message = 'argument index too small or too large' class MissingArgument(Error): message = 'missing argument' class ArgumentTypeMismatch(Error): message = 'argument type mismatch' class ArgumentNumberingMixture(Error): message = 'mixed numbered and unnumbered argument specifications' # errors in length modifiers: class LengthError(Error): message = 'invalid length modifier' # errors in flag characters: class FlagError(Error): message = 'unexpected format flag character' class RedundantFlag(Error): message = 'redundant flag character' # errors in field width: class WidthError(Error): message = 'unexpected width' class WidthRangeError(Error): message = 'field width too large' # errors in precision: class PrecisionError(Error): message = 'unexpected precision' class PrecisionRangeError(Error): message = 'precision too large' class VariableWidth(): type = 'int' def __init__(self, parent): self.parent = parent class VariablePrecision(): type = 'int' def __init__(self, parent): self.parent = parent class FormatString(): def __init__(self, s): self._items = items = [] self._argument_map = collections.defaultdict(list) self._next_arg_index = 1 self.warnings = [] last_pos = 0 for match in _directive_re.finditer(s): if match.start() != last_pos: raise Error( _printable_prefix(s[last_pos:]) ) last_pos = match.end() literal = match.group('literal') if literal is not None: items += [literal] else: items += [Conversion(self, match)] if last_pos != len(s): raise Error( _printable_prefix(s[last_pos:]) ) self.arguments = [] for i in range(1, NL_ARGMAX + 1): if not self._argument_map: break try: args = self._argument_map.pop(i) except KeyError: raise MissingArgument(s, i) self.arguments += [args] assert not self._argument_map self._argument_map = None for i, args in enumerate(self.arguments, start=1): types = frozenset(a.type for a in args) if len(types) > 1: raise ArgumentTypeMismatch(s, i, types) def add_argument(self, n, value): if self._argument_map is None: raise RuntimeError('arguments already initialized') if n is None: if self._next_arg_index is None: raise IndexError else: n = self._next_arg_index self._next_arg_index += 1 elif self._next_arg_index is None: pass elif self._next_arg_index == 1: assert not self._argument_map self._next_arg_index = None else: raise IndexError if n > NL_ARGMAX: raise OverflowError(n) self._argument_map[n] += [value] def warn(self, exc_type, *args, **kwargs): self.warnings += [exc_type(*args, **kwargs)] def get_last_integer_conversion(self, *, n): ''' return the integer conversion that consumes the last n arguments, or None ''' if n > len(self.arguments): raise IndexError if n <= 0: raise IndexError conv = vconv = None for i in range(len(self.arguments) - n, len(self.arguments)): assert i >= 0 for arg in self.arguments[i]: if isinstance(arg, (VariableWidth, VariablePrecision)): if vconv is None: vconv = arg.parent if vconv is not arg.parent: return elif isinstance(arg, Conversion): if vconv is None: vconv = arg if (conv is None) and (vconv is arg): conv = arg if conv is not arg: return else: assert False, f'type(arg) == {type(arg)!r}' # no coverage if conv is None: return if not conv.integer: return return conv def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) class Conversion(): type = None integer = None def __init__(self, parent, match): i = _info self._s = s = match.string[slice(*match.span())] # length and conversion: c99conversion = match.group('c99conv') c99length = match.group('c99len') length = match.group('length') conversion = match.group('conversion') tp = None self.integer = False if c99conversion is not None: assert c99length is not None if c99conversion in 'di': tp = 'int' elif c99conversion in 'ouxX': tp = 'uint' else: # should not happen assert False # no coverage conversion = c99conversion if c99length.startswith(('LEAST', 'FAST')): tp += '_' + c99length.lower() else: tp += c99length.lower() tp += '_t' self.integer = True elif conversion in i.int_cvt + 'n': plength = i.portable_int_lengths.get(length, length) if plength != length: parent.warn(NonPortableConversion, s, '%' + length + conversion, '%' + plength + conversion ) tp = i.int_types.get(plength or '') # pylint: disable=no-member assert tp is not None tp = tp[conversion in i.uint_cvt] if conversion == 'n': tp += ' *' else: self.integer = True elif conversion in i.float_cvt: if length is None: tp = 'double' elif length == 'l': # XXX C99 says that the “l” length is no-op for floating-point # conversions, but this is not documented in the printf(3) # manpage. parent.warn(NonPortableConversion, s, '%l' + conversion, '%' + conversion ) tp = 'double' elif length == 'L': tp = 'long double' elif conversion == 'c': if length is None: tp = 'char' # C99 says it's an int, which is then converted to unsigned char. # We don't want “int” here, so that %c and %d have distinct types. # Mere “char” is not very precise, but it should be good enough. elif length == 'l': tp = 'wint_t' elif conversion == 'C': if length is None: parent.warn(NonPortableConversion, s, '%C', '%lc') tp = 'wint_t' elif conversion == 's': if length is None: tp = 'const char *' elif length == 'l': tp = 'const wchar_t *' elif conversion == 'S': if length is None: parent.warn(NonPortableConversion, s, '%S', '%ls') tp = 'const wchar_t *' elif conversion == 'p': if length is None: tp = 'void *' elif conversion in {'m', '%'}: if length is None: tp = 'void' else: # should not happen assert False # no coverage if tp is None: assert length is not None raise LengthError(s, length) self.type = tp # flags: flags = collections.Counter(match.group('flags')) for flag, count in flags.items(): if count != 1: parent.warn(RedundantFlag, s, flag, flag) if conversion == 'n': # C99 says that the “n” conversion cannot include any flags, # but this is not documented in the printf(3) manpage. # https://bugs.debian.org/756602 raise FlagError(s, flag) if flag == '#': if conversion not in i.oct_cvt + i.hex_cvt + i.float_cvt: raise FlagError(s, flag) elif flag == '0': if conversion not in i.int_cvt + i.float_cvt: raise FlagError(s, flag) elif flag == "'": if conversion not in i.dec_cvt: raise FlagError(s, flag) else: if conversion == '%': raise FlagError(s, flag) assert flag in {'-', ' ', '+', 'I'} for f1, f2 in [('-', '0'), ('+', ' ')]: if (f1 in flags) and (f2 in flags): parent.warn(RedundantFlag, s, f1, f2) # width: width = match.group('width') if width is not None: width = int(width) if width > INT_MAX: raise WidthRangeError(s, width) elif match.group('varwidth'): varwidth_index = match.group('varwidth_index') if varwidth_index is not None: varwidth_index = int(varwidth_index.rstrip('$')) if not (0 < varwidth_index <= NL_ARGMAX): raise ArgumentRangeError(s, varwidth_index) try: parent.add_argument(varwidth_index, VariableWidth(self)) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError as exc: raise ArgumentRangeError(s, f'{exc}$') width = ... if width is not None: if conversion in '%n': # C99 says that the “n” conversion cannot include a field width, # but this is not documented in the printf(3) manpage. # https://bugs.debian.org/756602 raise WidthError(s) # precision: precision = match.group('precision') if precision is not None: precision = int(precision or '0') if precision > INT_MAX: raise PrecisionRangeError(s) elif match.group('varprec'): varprec_index = match.group('varprec_index') if varprec_index is not None: varprec_index = int(varprec_index.rstrip('$')) if not (0 < varprec_index <= NL_ARGMAX): raise ArgumentRangeError(s, varprec_index) try: parent.add_argument(varprec_index, VariablePrecision(self)) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError as exc: raise ArgumentRangeError(s, f'{exc}$') precision = ... if precision is not None: if conversion in i.int_cvt + i.float_cvt + i.str_cvt: pass else: # XXX C99 says that precision for the other conversion is # undefined behavior, but this is not documented in the # printf(3) manpage. raise PrecisionError(s) if (conversion in i.int_cvt) and ('0' in flags): parent.warn(RedundantFlag, s, '0') # index: index = match.group('index') if index is not None: index = int(index.rstrip('$')) if not (0 < index <= NL_ARGMAX): raise ArgumentRangeError(s, index) if tp == 'void': if index is not None: if conversion == '%': raise ForbiddenArgumentIndex(s) else: # Although not specifically forbidden, having an argument index # for %m (which doesn't consume any argument) doesn't make any # sense. TODO: Emit a warning. pass # XXX The printf(3) manpage says that numbered arguments can be # mixed only with %%. But practically, mixing them with %m (which # also doesn't consume any argument) must be also allowed. else: try: parent.add_argument(index, self) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError as exc: raise ArgumentRangeError(s, f'{exc}$') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/strformat/perlbrace.py0000644000000000000000000000436414275257143021077 0ustar00rootroot00000000000000# Copyright © 2016-2020 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' Perl format checks: Locale::TextDomain ''' import re _field_re = re.compile(r''' (?P [^{]+ ) | (?: [{] (?P [^\W\d]\w* ) [}] ) ''', re.VERBOSE) def _printable_prefix(s, r=re.compile('[ -\x7E]+')): return r.match(s).group() class Error(Exception): message = 'invalid placeholder specification' class FormatString(): def __init__(self, s): self._items = items = [] arguments = set() last_pos = 0 for match in _field_re.finditer(s): if match.start() != last_pos: raise Error( _printable_prefix(s[last_pos:]) ) items += [match.group()] argname = match.group('name') if argname is not None: arguments.add(argname) last_pos = match.end() if last_pos != len(s): raise Error( _printable_prefix(s[last_pos:]) ) self.arguments = frozenset(arguments) def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/strformat/pybrace.py0000644000000000000000000002150214275257143020556 0ustar00rootroot00000000000000# Copyright © 2016-2020 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string format checks: Python's str.format() ''' import collections import functools import re _field_name_pattern = r''' (?: \d+ | [^\W\d]\w* ) (?: [.] [^\W\d]\w* | \[ [^]]+ \] )* ''' _simple_field_pattern = '[{] (?:' + _field_name_pattern + ') ? [}]' _simple_field_re = re.compile(_simple_field_pattern, re.VERBOSE) _field_re = re.compile(r''' (?P (?: [^{}] | [{]{2} | [}]{2} )+ ) | (?: [{] (?: (?P''' + _field_name_pattern + r''') ? (?P ! \w+ ) ? (?P : (?: [^{}]* | ''' + _simple_field_pattern + ''' )* ) ? ) [}] ) ''', re.VERBOSE) _format_spec_re = re.compile( # (this regex doesn't take nested fields into account) r''' \A (?: (?P [^}] ) ? (?P [<>=^] ) ) ? (?P [ +-] ) ? (?P [#] ) ? (?P [0] ) ? (?P [0-9]+ ) ? (?P [,] ) ? (?: [.] (?P \d+) ) ? (?P [\w%]) ? \Z ''', re.VERBOSE) def _printable_prefix(s, r=re.compile('[ -\x7E]+')): return r.match(s).group() # -------------------------------------------------------------------------- SSIZE_MAX = (1 << 31) - 1 # on 32-bit architectures # -------------------------------------------------------------------------- class Error(Exception): message = 'invalid replacement field specification' class ConversionError(Error): message = 'invalid conversion flag' class FormatError(Error): message = 'invalid format specification' class FormatTypeMismatch(Error): message = 'type mismatch between conversion and format specifications' # errors in argument indexing: class ArgumentNumberingMixture(Error): message = 'mixed numbered and unnumbered argument specifications' class ArgumentRangeError(Error): message = 'argument index too large' class ArgumentTypeMismatch(Error): message = 'argument type mismatch' # -------------------------------------------------------------------------- class FormatString(): def __init__(self, s): self._argument_map = collections.defaultdict(list) self._next_arg_index = 0 self._items = items = [] last_pos = 0 for match in _field_re.finditer(s): if match.start() != last_pos: raise Error( _printable_prefix(s[last_pos:]) ) last_pos = match.end() literal = match.group('literal') if literal is not None: items += [literal] else: items += [Field(self, match)] if last_pos != len(s): raise Error( _printable_prefix(s[last_pos:]) ) for name, args in self._argument_map.items(): common_types = functools.reduce( frozenset.__and__, (a.types for a in args) ) if not common_types: raise ArgumentTypeMismatch(s, name) for arg in args: arg.types = common_types self.argument_map = dict(self._argument_map) self._argument_map = None def add_argument(self, name, field): if self._argument_map is None: raise RuntimeError('arguments already initialized') if name is None: if self._next_arg_index is None: raise IndexError n = self._next_arg_index if n > SSIZE_MAX: raise OverflowError(n) self._next_arg_index += 1 self._argument_map[n] += [field] elif name.isdigit(): n = int(name) if n > SSIZE_MAX: raise OverflowError(n) if self._next_arg_index is None: pass elif self._next_arg_index == 0: self._next_arg_index = None else: raise IndexError self._argument_map[n] += [field] else: self._argument_map[name] += [field] def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) # -------------------------------------------------------------------------- class Field(): def __init__(self, parent, match): s = match.string[slice(*match.span())] name = match.group('name') try: parent.add_argument(name, self) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError: raise ArgumentRangeError(s) fmt = match.group('format') tp = {'str', 'int', 'float'} if fmt is None: pass elif '{' in fmt: # Nested replacement fields are nasty. They make virtually # impossible to do any type checking. For example: # # >>> '{:{}{}}'.format('m', 'o<2', 3) # 'moooooooooooooooooooooo' # >>> '{:{}{}}'.format(23, '+', 'x') # '+17' # for subfield in _simple_field_re.findall(fmt): assert subfield[0] == '{' assert subfield[-1] == '}' subfield_name = subfield[1:-1] or None subfield = NestedField(self) try: parent.add_argument(subfield_name, subfield) except IndexError: raise ArgumentNumberingMixture(subfield) except OverflowError: raise ArgumentRangeError(s) else: assert fmt[0] == ':' fmatch = _format_spec_re.match(fmt[1:]) if fmatch is None: raise FormatError(s) comma = fmatch.group('comma') ftype = fmatch.group('type') if ftype is None: pass elif ftype == 's': tp = {'str'} elif ftype in 'bcdoxX': tp = {'int'} elif ftype in 'eEfFgG%': tp = {'float'} elif ftype == 'n': if comma: raise FormatError(s) tp = {'int', 'float'} else: raise Error(s) alt = fmatch.group('alt') sign = fmatch.group('sign') if alt or sign or comma: tp &= {'int', 'float'} if not tp: raise FormatError(s) align = fmatch.group('align') zero = fmatch.group('zero') if (align is None) and (zero is not None): align = '=' if align == '=': tp &= {'int', 'float'} if not tp: raise FormatError(s) width = fmatch.group('width') if width is not None: width = int(width) if width > SSIZE_MAX: raise FormatError(s) precision = fmatch.group('precision') if precision is not None: tp &= {'float', 'str'} if not tp: raise FormatError(s) precision = int(precision) if precision > SSIZE_MAX: raise FormatError(s) conversion = match.group('conversion') if conversion is None: pass elif conversion in {'!s', '!r', '!a'}: if 'str' not in tp: raise FormatTypeMismatch(s) else: raise ConversionError(s) self.types = frozenset(tp) class NestedField(): types = frozenset({'str', 'int', 'float'}) def __init__(self, parent): self.parent = parent # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/strformat/python.py0000644000000000000000000002313614275257143020457 0ustar00rootroot00000000000000# Copyright © 2015-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string format checks: Python's %-formatting ''' import collections import io class _info: flags = '#0- +' lengths = 'hlL' oct_cvt = 'o' hex_cvt = 'xX' int_cvt = oct_cvt + hex_cvt + 'diu' float_cvt = 'eEfFgG' other_cvt = 'csra' all_cvt = int_cvt + float_cvt + other_cvt + '%' SSIZE_MAX = (1 << 31) - 1 # on 32-bit architectures # -------------------------------------------------------------------------- class Error(Exception): message = 'invalid conversion specification' class ObsoleteConversion(Error): message = 'obsolete conversion specifier' # errors in argument indexing: class ForbiddenArgumentKey(Error): message = 'argument key not allowed' class ArgumentIndexingMixture(Error): message = 'mixed named and unnamed argument specifications' class ArgumentTypeMismatch(Error): message = 'argument type mismatch' # errors is flags: class RedundantFlag(Error): message = 'redundant flag character' # errors in field width: class WidthRangeError(Error): message = 'field width too large' # errors in precision: class RedundantPrecision(Error): message = 'redundant precision' class PrecisionRangeError(Error): message = 'precision too large' # errors in length modifiers: class RedundantLength(Error): message = 'redundant length modifier' # -------------------------------------------------------------------------- class VariableWidth(): type = 'int' def __init__(self, parent): self.parent = parent class VariablePrecision(): type = 'int' def __init__(self, parent): self.parent = parent # -------------------------------------------------------------------------- class FormatString(): def __init__(self, s): self._items = items = [] self._seq_arguments = [] self._map_arguments = collections.defaultdict(list) self.warnings = [] text = io.StringIO() si = enumerate(s) i = 0 def next_si(): try: return next(si) except StopIteration: raise Error(s[i:]) while True: try: i, ch = next(si) except StopIteration: if text.tell(): items += [text.getvalue()] break if ch != '%': text.write(ch) continue j, ch = next_si() key = None if ch == '(': # XXX Python skips over balanced parentheses, but this is not documented. pcount = 1 while True: j, ch = next_si() if ch == '(': pcount += 1 elif ch == ')': pcount -= 1 if pcount == 0: j, ch = next_si() break key = s[i+2:j-1] flags = collections.Counter() while ch in _info.flags: flags[ch] += 1 j, ch = next_si() width = None var_width = False if ch == '*': var_width = True j, ch = next_si() else: width = 0 while '0' <= ch <= '9': width *= 10 width += int(ch) j, ch = next_si() prec = None var_prec = False if ch == '.': j, ch = next_si() if ch == '*': var_prec = True j, ch = next_si() else: prec = 0 while '0' <= ch <= '9': prec *= 10 prec += int(ch) j, ch = next_si() length = None if ch in _info.lengths: length = ch j, ch = next_si() if ch in _info.all_cvt: conv = ch else: raise Error(s[i:]) if text.tell(): items += [text.getvalue()] text.seek(0) text.truncate() items += [Conversion(self, s[i:j+1], key=key, flags=flags, width=width, var_width=var_width, prec=prec, var_prec=var_prec, length=length, conv=conv, )] self.seq_arguments = self._seq_arguments self.seq_conversions = [ arg for arg in self._seq_arguments if isinstance(arg, Conversion) ] for key, args in self._map_arguments.items(): types = frozenset(a.type for a in args) if len(types) > 1: raise ArgumentTypeMismatch(s, key, types) self.map_arguments = self._map_arguments self._map_arguments = self._seq_arguments = None def add_argument(self, key, arg): if self._map_arguments is None: raise RuntimeError('arguments already initialized') # Python accepts mixed named and unnamed arguments # in some corner cases: # https://bugs.python.org/issue1467929 # We follow the documentation and reject such mixtures. if key is None: if self._map_arguments: raise IndexError self._seq_arguments += [arg] else: if self._seq_arguments: raise IndexError self._map_arguments[key] += [arg] def warn(self, exc_type, *args, **kwargs): self.warnings += [exc_type(*args, **kwargs)] def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) # -------------------------------------------------------------------------- class Conversion(): def __init__(self, parent, s, *, key, flags, width, var_width, prec, var_prec, length, conv): assert s[-1] == conv, f'{s[-1]} != {conv}' i = _info for flag, count in flags.items(): if count != 1: parent.warn(RedundantFlag, s, flag, flag) if flag == '#': if conv not in i.oct_cvt + i.hex_cvt + i.float_cvt: parent.warn(RedundantFlag, s, flag) elif flag == '-': pass else: assert flag in '0 +' if conv not in i.int_cvt + i.float_cvt: parent.warn(RedundantFlag, s, flag) for f1, f2 in [('-', '0'), ('+', ' ')]: if (f1 in flags) and (f2 in flags): parent.warn(RedundantFlag, s, f1, f2) if var_width: assert width is None try: parent.add_argument(None, VariableWidth(self)) except IndexError: raise ArgumentIndexingMixture(s) width = ... elif width > SSIZE_MAX: # The limit is INT_MAX in Python 2.X and SSIZE_MAX in Python 3.X; # but INT_MAX == SSIZE_MAX on mainstream 32-bit architectures. raise WidthRangeError(s, width) if var_prec: assert prec is None try: parent.add_argument(None, VariablePrecision(self)) except IndexError: raise ArgumentIndexingMixture(s) prec = ... elif prec is not None: if prec > SSIZE_MAX: raise PrecisionRangeError(s, width) if prec is not None: if (conv in i.int_cvt) and ('0' in flags): parent.warn(RedundantFlag, s, '0') if conv in 'c%': parent.warn(RedundantPrecision, s, prec) if length is not None: parent.warn(RedundantLength, s, length) if conv in i.int_cvt: tp = 'int' if conv == 'u': parent.warn(ObsoleteConversion, s, '%u', '%d') elif conv in i.float_cvt: tp = 'float' elif conv == 'c': tp = 'chr' elif conv == 's': tp = 'str' elif conv in 'ra': tp = 'object' elif conv == '%': tp = 'None' else: assert False # no coverage self.type = tp if tp == 'None': if key is not None: raise ForbiddenArgumentKey(s) else: try: parent.add_argument(key, self) except IndexError: raise ArgumentIndexingMixture(s) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/tags.py0000644000000000000000000001364314275257143016055 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' tag support ''' import configparser import enum import functools import os import re from lib import misc from lib import paths from lib import terminal @functools.total_ordering class OrderedEnum(enum.Enum): def __lt__(self, other): if not type(self) is type(other): return NotImplemented return self.value < other.value # pylint: disable=comparison-with-callable def __eq__(self, other): if not type(self) is type(other): return NotImplemented return self.value == other.value # pylint: disable=comparison-with-callable def __hash__(self): # pylint: disable=invalid-hash-returned return self.value severities = OrderedEnum('Severity', [ # pylint: disable=too-many-function-args 'pedantic', 'wishlist', 'minor', 'normal', 'important', 'serious', ]) certainties = OrderedEnum('Certainty', [ # pylint: disable=too-many-function-args 'wild-guess', 'possible', 'certain', ]) class InvalidSeverity(misc.DataIntegrityError): pass class InvalidCertainty(misc.DataIntegrityError): pass class UnknownField(misc.DataIntegrityError): pass _is_safe = re.compile(r'\A[A-Za-z0-9_.!<>=-]+\Z').match class safestr(str): pass def _escape(s): if isinstance(s, safestr): return s if isinstance(s, bytes): return repr(s)[1:] s = str(s) if s == '': return '(empty string)' elif _is_safe(s): return s else: return repr(s) def safe_format(template, *args, **kwargs): args = [_escape(s) for s in args] kwargs = {k: _escape(v) for k, v in kwargs.items()} return safestr(template.format(*args, **kwargs)) class Tag(): def __init__(self, **kwargs): self.description = None self.references = [] for k, v in kwargs.items(): try: getattr(self, '_set_' + k)(v) except AttributeError: raise UnknownField(k) type({self.name, self.severity, self.certainty}) # pylint: disable=attribute-defined-outside-init def _set_name(self, value): self.name = value def _set_severity(self, value): try: self.severity = severities[value] except KeyError as exc: [key] = exc.args raise InvalidSeverity(key) def _set_certainty(self, value): try: self.certainty = certainties[value] except KeyError as exc: [key] = exc.args raise InvalidCertainty(key) # pylint: enable=attribute-defined-outside-init _strip_leading_dot = functools.partial( re.compile('^[.]', re.MULTILINE).sub, '' ) @classmethod def _parse_multiline(cls, value): for s in value.splitlines(): if not s or s.isspace(): continue yield cls._strip_leading_dot(s) def _set_description(self, value): value = str.join('\n', self._parse_multiline(value)) self.description = value def _set_references(self, value): self.references += self._parse_multiline(value) def get_colors(self): prio = self.get_priority() n = dict( P=terminal.colors.green, I=terminal.colors.cyan, W=terminal.colors.yellow, E=terminal.colors.red, )[prio] return ( terminal.attr_fg(n), terminal.attr_reset() ) def get_priority(self): s = self.severity S = severities c = self.certainty C = certainties # pylint: disable=no-member return { S.pedantic: 'P', S.wishlist: 'I', S.minor: 'IW'[c >= C.certain], S.normal: 'IW'[c >= C.possible], S.important: 'WE'[c >= C.possible], S.serious: 'E', }[s] # pylint: enable=no-member def format(self, target, *extra, color=False): if color: color_on, color_off = self.get_colors() else: color_on = color_off = '' s = f'{self.get_priority()}: {target}: {color_on}{self.name}{color_off}' if extra: s += ' ' + str.join(' ', map(_escape, extra)) return s def _read_tags(): path = os.path.join(paths.datadir, 'tags') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') misc.check_sorted(cp) tags = {} for tagname, section in cp.items(): if not tagname: continue kwargs = dict(section.items()) kwargs['name'] = tagname tags[tagname] = Tag(**kwargs) return tags _tags = _read_tags() def tag_exists(tagname): return tagname in _tags def iter_tags(): return (tag for _, tag in sorted(_tags.items())) def get_tag(tagname): return _tags[tagname] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/terminal.py0000644000000000000000000000533414275257143016730 0ustar00rootroot00000000000000# Copyright © 2012-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' color terminal support ''' import functools import re class _dummy_curses: @staticmethod def tigetstr(*args, **kwargs): del args, kwargs return b'' @staticmethod def tparm(*args, **kwargs): del args, kwargs return b'' _curses = _dummy_curses class colors: black = NotImplemented red = NotImplemented green = NotImplemented yellow = NotImplemented blue = NotImplemented magenta = NotImplemented cyan = NotImplemented white = NotImplemented _strip_delay = functools.partial( re.compile(b'[$]<([0-9]*[.])?[0-9]+([/*]|[*][/])?>').sub, b'' ) def attr_fg(i): ''' returns a string that changes the foreground color ''' s = _curses.tigetstr('setaf') or b'' s = _strip_delay(s) if s: # work-around for https://bugs.debian.org/902630 s = _curses.tparm(s, i) return s.decode() def attr_reset(): ''' returns a string that resets all attributes ''' s = _curses.tigetstr('sgr0') or b'' s = _strip_delay(s) return s.decode() def initialize(): ''' initialize the terminal ''' global _curses # pylint: disable=global-statement try: import curses as _curses # pylint: disable=redefined-outer-name,import-outside-toplevel except ImportError: return try: _curses.setupterm() except _curses.error: _curses = _dummy_curses return for key, value in vars(_curses).items(): if key.startswith('COLOR_'): key = key[6:].lower() getattr(colors, key) setattr(colors, key, value) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/lib/xml.py0000644000000000000000000000462514275257143015717 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' XML support ''' import random import string import xml.parsers.expat SyntaxError = xml.parsers.expat.ExpatError # pylint: disable=redefined-builtin _xe = ( 'i18nspector.' + str.join('', (random.choice(string.ascii_lowercase) for x in range(12))) ) _source = '''\ ]> &{xe}; '''.format(xe=_xe).encode('ASCII') def check_fragment(s): ''' check if the string could be a well-formed XML fragment ''' def ee_handler(context, base, systemid, publicid): assert base is None assert systemid == _xe assert publicid is None eparser = parser.ExternalEntityParserCreate(context) eparser.Parse(s.encode('UTF-8'), True) return 1 parser = xml.parsers.expat.ParserCreate('UTF-8') parser.ExternalEntityRefHandler = ee_handler parser.Parse(_source, True) # https://www.w3.org/TR/REC-xml/#NT-NameStartChar # pylint: disable=line-too-long _start_char = ':A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\U00010000-\U000EFFFF' _next_char = _start_char + '.0-9\xB7\u0300-\u036F\u203F\u2040-' name_re = f'[{_start_char}][{_next_char}]*' # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/0000755000000000000000000000000014275257157015447 5ustar00rootroot00000000000000i18nspector-0.27.1/private/add-languages0000755000000000000000000000546114275257143020072 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import functools import subprocess as ipc import sys import json int(0_0) # Python >= 3.6 is required @functools.lru_cache() def get_iso_codes_dir(): prefix = ipc.check_output(['pkg-config', 'iso-codes', '--variable=prefix']) prefix = prefix.decode('ASCII').strip() return f'{prefix}/share/iso-codes/json' def main(): ap = argparse.ArgumentParser() ap.add_argument('languages', metavar='LANG', nargs='+') options = ap.parse_args() languages = set(options.languages) path = get_iso_codes_dir() + '/iso_639-2.json' with open(path, 'rt', encoding='UTF-8') as file: data = json.load(file) for item in data['639-2']: ll = item.get('alpha_2') lll_t = item.get('alpha_3') lll_b = item.get('bibliographic') requested = None for lang in ll, lll_b, lll_t: if lang in languages: assert lang is not None requested = lang languages.remove(lang) if requested is None: continue lang = ll or lll_t if lang is None: raise ValueError names = [ s.strip() for s in item.get('name').split(';') ] print(f'[{requested}]') if lang != requested: print(f'# XXX mapping {requested} => {lang}') if len(names) == 1: print('names =', *names) else: print('names =') for name in names: print('', name) print() for lang in sorted(languages): print(f'# Unknown language code: {lang}') sys.exit(len(languages) > 0) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/check-rst0000755000000000000000000000302714275257143017255 0ustar00rootroot00000000000000#!/bin/sh # Copyright © 2016-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -e -u here=${0%/*} here=${here#./} root="$here/../" root=${root#private/../} rst2xml=$(command -v rst2xml) \ || rst2xml=$(command -v rst2xml.py) \ || { printf 'rst2xml not found\n' >&2; exit 1; } rst2xml=${rst2xml##*/} options='--input-encoding=UTF-8 --strict' if [ $# -eq 0 ] then grep -rwl 'ft=rst' "${root}doc" else printf '%s\n' "$@" fi | xargs -t -I{} "$rst2xml" $options {} /dev/null # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/collect-characters0000755000000000000000000000620714275257143021137 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import collections import functools import itertools import os import sys import polib int(0_0) # Python >= 3.6 is required def init_polib(): # don't assume UTF-8 encoding polib.default_encoding = 'ASCII' def main(): init_polib() ap = argparse.ArgumentParser() ap.add_argument('files', metavar='FILE', nargs='+') ap.add_argument('--skip-ascii', action='store_true', help='skip ASCII characters') ap.add_argument('--stdin', action='store_true', help='read filenames from stdin') options = ap.parse_args() files = options.files if options.stdin: files = itertools.chain( files, (l.rstrip() for l in sys.stdin) ) char_counter = collections.Counter() char_files = collections.defaultdict(set) n_files = 0 eprint = functools.partial(print, file=sys.stderr, flush=True) for path in files: eprint(path, end=' ... ') try: extension = os.path.splitext(path)[-1] if extension == '.po': constructor = polib.pofile elif extension in {'.mo', '.gmo'}: constructor = polib.mofile else: raise NotImplementedError(repr(extension)) file = constructor(path) for message in file.translated_entries(): for text in itertools.chain([message.msgstr], message.msgstr_plural.values()): for ch in text: char_counter[ch] += 1 char_files[ch].add(path) file = None except Exception as exc: # pylint: disable=broad-except eprint('error:', exc) else: eprint('ok') n_files += 1 for n, ch in sorted(((n, ch) for ch, n in char_counter.items()), reverse=True): if options.skip_ascii and ord(ch) < 0x80: continue filecov = len(char_files[ch]) / n_files print(f'{n:6} [{filecov:6.1%}] {ch!r}') if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/collect-metadata0000755000000000000000000001116114275257143020573 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import collections import functools import itertools import os import re import sys import polib int(0_0) # Python >= 3.6 is required def init_polib(): # Happily decode any file, even when encoding declaration is broken or # missing. polib.default_encoding = 'ISO-8859-1' is_sane_field_name = re.compile('^[a-zA-Z-]+$').match _extract_address = re.compile(r'''^(?: .*< ( [^<>]+@[^<>]+ ) >\s* | ( \S+@\S+ ) | .*< ( https?://[^<>]+ ) >\s* | .*[(] ( https?://[^()]+ ) [)]\s* | \s* (https?://\S+) \s* )$''', re.VERBOSE).match def extract_address(s): match = _extract_address(s) if match is None: return [result] = filter(None, match.groups()) return result def main(): init_polib() ap = argparse.ArgumentParser() ap.add_argument('files', metavar='FILE', nargs='+') ap.add_argument('-F', '--field', help='only this field') ap.add_argument('--insane', action='store_true', help='allow insane field names') ap.add_argument('--extract-addresses', action='store_true') ap.add_argument('--all-test-cases', action='store_true') ap.add_argument('--plural-only', action='store_true', help='consider only translations with plural forms') ap.add_argument('--stdin', action='store_true', help='read filenames from stdin') options = ap.parse_args() metadata = collections.defaultdict(collections.Counter) if options.all_test_cases: test_cases = collections.defaultdict(set) else: test_cases = {} files = options.files if options.stdin: files = itertools.chain( files, (l.rstrip() for l in sys.stdin) ) eprint = functools.partial(print, file=sys.stderr, flush=True) for path in files: eprint(path, end=' ... ') try: extension = os.path.splitext(path)[-1] if extension == '.po': constructor = polib.pofile elif extension in {'.mo', '.gmo'}: constructor = polib.mofile else: raise NotImplementedError(repr(extension)) file = constructor(path) if options.plural_only: for msg in file.translated_entries(): if msg.msgstr_plural: break else: eprint('skip') continue for k, v in file.metadata.items(): if (not is_sane_field_name(k)) and (not options.insane): continue if not (options.field is None or k == options.field): continue if options.extract_addresses: v = extract_address(v) metadata[k][v] += 1 if options.all_test_cases: test_cases[k, v].add(path) else: test_cases[k, v] = path file = None except Exception as exc: # pylint: disable=broad-except eprint('error:', exc) else: eprint('ok') for key, values in sorted(metadata.items()): print(f'{key!r}:') for value, n in values.most_common(): if options.all_test_cases: print(f' {n:6} {value!r}') for path in sorted(test_cases[key, value]): print(f' + {path!r}') else: path = test_cases[key, value] print(f' {n:6} {value!r}; test-case: {path!r}') if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/online-build-po-corpus0000755000000000000000000001775214275257143021712 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import contextlib import gzip import os import re import subprocess import sys import tarfile import tempfile import urllib.parse import apt import apt_pkg int(0_0) # Python >= 3.6 is required def is_po_path(path): return path.endswith(('.po', '.pot')) class Fetcher(): def __init__(self, urlbase): self._urlbase = urlbase self._progress = apt.progress.text.AcquireProgress() self._acquire = apt_pkg.Acquire(self._progress) self._files = [] self._tmpdir = tempfile.TemporaryDirectory(prefix='i18nspector.private.') # pylint: disable=consider-using-with def add(self, url, name, urlbase=None): if urlbase is None: urlbase = self._urlbase url = urllib.parse.urljoin(urlbase, url) self._files += [apt_pkg.AcquireFile( self._acquire, uri=url, descr=url, destfile=os.path.join(self._tmpdir.name, name) )] def run(self): acq = self._acquire rc = acq.run() if rc != acq.RESULT_CONTINUE: raise RuntimeError('fetching failed') for acqfile in self._files: if acqfile.status != acqfile.STAT_DONE: raise RuntimeError('fetching failed') yield acqfile.destfile def __enter__(self): return self def __exit__(self, exc, value, tb): self.close() def close(self): self._tmpdir.cleanup() _package_name_re = re.compile(r'\A[a-z0-9][a-z0-9.+-]+\Z') def validate_package_name(pkg): if _package_name_re.match(pkg): pass else: raise RuntimeError(f'invalid package name: {pkg!r}') @contextlib.contextmanager def chdir(new_cwd): orig_cwd = os.getcwd() try: os.chdir(new_cwd) yield finally: os.chdir(orig_cwd) default_mirror = 'https://deb.debian.org/debian' default_dist = 'stable' default_areas = 'main' def main(): ap = argparse.ArgumentParser() ap.add_argument('--mirror', metavar='URL', default=default_mirror, help=f'Debian mirror to use (default: {default_mirror})' ) ap.add_argument('--contents-mirror', metavar='URL', default=None, help='Debian mirror of Contents-* files to use (default: same as --mirror)' ) ap.add_argument('--distribution', metavar='DIST', default=default_dist, help=f'Debian distribution to use (default: {default_dist})' ) ap.add_argument('--areas', metavar='AREA[,AREA...]', default=default_areas, help=f'archive areas to use (default: {default_areas})' ) ap.add_argument('--output', metavar='TARFILE', required=True, help='output tar file' ) options = ap.parse_args() output = options.output tarmode = 'w|' for ext in 'gz', 'bz2', 'xz': if options.output.endswith('.' + ext): tarmode += ext break tar = tarfile.open(output, mode=tarmode) # pylint: disable=consider-using-with mirror = options.mirror cnts_mirror = options.contents_mirror if cnts_mirror is None: cnts_mirror = mirror dist = options.distribution areas = options.areas.split(',') def tarfilter(tarinfo): tarinfo.uid = tarinfo.gid = 0 tarinfo.uname = tarinfo.gname = 'root' tarinfo.mode &= 0o700 tarinfo.mode |= 0o644 if tarinfo.mode & 0o100: tarinfo.mode |= 0o111 prefix = f'po-corpus-{dist}/' tarinfo.name = prefix + tarinfo.name if tarinfo.linkname: tarinfo.linkname = prefix + tarinfo.linkname return tarinfo subprocess.check_call(['dpkg-source', '--version'], stdout=subprocess.DEVNULL) for area in areas: urlbase = f'{mirror}/dists/{dist}/{area}/' cnts_urlbase = f'{cnts_mirror}/dists/{dist}/{area}/' with Fetcher(urlbase=urlbase) as fetcher: fetcher.add('Contents-source.gz', 'Contents.gz', urlbase=cnts_urlbase) fetcher.add('source/Sources.xz', 'Sources.xz') [contents_path, sources_path] = fetcher.run() interesting_packages = set() with gzip.open(contents_path, 'rt', encoding='UTF-8', newline='\n') as file: for line in file: try: path, packages = line.rsplit('\t', 1) except ValueError: raise RuntimeError(f'malformed line: {line!r}') if is_po_path(path): packages = packages.rstrip('\n').split(',') for pkg in packages: validate_package_name(pkg) interesting_packages.update(packages) for para in apt_pkg.TagFile(sources_path): pkg = para['Package'] if pkg not in interesting_packages: continue fileinfo = para['Files'].splitlines() dscname = None names = set() for line in fileinfo: _, name = line.rsplit(' ', 1) ok = ( name.startswith(pkg + '_') and '/' not in name and name not in names ) if not ok: raise RuntimeError(f'Package {pkg}: bad Files line: {line!r}') names.add(name) if name.endswith('.dsc'): if dscname is not None: raise RuntimeError(f'Package {pkg}: duplicate .dsc file') dscname = name if dscname is None: raise RuntimeError(f'Package {pkg}: missing .dsc file') names = list(names) names.sort(key=dscname.__eq__) pkgdir = para['Directory'] pkgurlbase = f'{mirror}/{pkgdir}/' with Fetcher(urlbase=pkgurlbase) as pkgfetcher: for name in names: pkgfetcher.add(name, name) for path in pkgfetcher.run(): pass dscpath = path unpacked = dscpath[:-4] subprocess.check_call(['dpkg-source', '-x', dscpath, unpacked], stdout=sys.stderr) with chdir(os.path.dirname(unpacked)): for unp_root, unp_dirs, unp_files in os.walk(os.path.basename(unpacked)): try: unp_dirs.remove('.pc') except ValueError: pass for unp_file in unp_files: if is_po_path(unp_file): unp_path = os.path.join(unp_root, unp_file) tar.add(unp_path, filter=tarfilter) tar.close() if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/online-check-gettext-data0000755000000000000000000001351114275257143022321 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import re import sys import urllib.request sys.path[0] += '/..' from lib import gettext from lib import ling int(0_0) # Python >= 3.6 is required def strip_plural_forms(s): # Remove superfluous parentheses around the plural formula: return re.sub(r'\bplural=\((.*?)\);$', r'plural=\1;', s) def do_plurals(): regexp = re.compile(r'\s+{\s*"([a-zA-Z_]+)".*"(nplurals.*?)"') url = 'https://git.savannah.gnu.org/cgit/gettext.git/plain/gettext-tools/src/plural-table.c' okay = set() with urllib.request.urlopen(url) as file: for line in file: line = line.decode('ASCII').rstrip() match = regexp.match(line) if match is None: continue language, gettext_plural_forms = match.groups() language = ling.parse_language(language) gettext_plural_forms = strip_plural_forms(gettext_plural_forms) our_plural_forms = language.get_plural_forms() or [] if gettext_plural_forms not in our_plural_forms: print(f'[{language}]') if our_plural_forms: if len(our_plural_forms) == 1: print('# plural-forms =', *our_plural_forms) else: print('# plural-forms =') for pf in our_plural_forms: print('# ', pf) print('plural-forms =', gettext_plural_forms) print() else: okay.add(str(language)) n_okay = len(okay) print(f'# No plural-forms changes required for {n_okay} languages') print() blacklist = { # https://lists.gnu.org/archive/html/bug-gettext/2015-06/msg00057.html ('pap', 'AN'), } def do_languages(): url = 'https://git.savannah.gnu.org/cgit/gettext.git/plain/gettext-tools/src/msginit.c' okay = set() with urllib.request.urlopen(url) as file: contents = file.read() match = re.compile(br'locales_with_principal_territory\s*\[\]\s*=\s*[{](.*?)[}]', re.DOTALL).search(contents) if match is None: raise ValueError contents = match.group(1) contents = re.compile(br'/[*].*?[*]/', re.DOTALL).sub(b'', contents) contents = contents.decode('ASCII') data = {} primary_languages = set(ling.get_primary_languages()) for item in re.findall(r'"(\w+)"', contents): language, gettext_cc = item.split('_') if language not in primary_languages: continue data[language] = gettext_cc our_cc = ling.parse_language(language).get_principal_territory_code() if our_cc != gettext_cc: if (language, gettext_cc) in blacklist: if our_cc is not None: okay.add(language) continue print(f'[{language}]') if our_cc is not None: print('# WAS: principal-territory =', our_cc) if ling.lookup_territory_code(gettext_cc) is None: print('# BAD: principal-territory =', gettext_cc) else: print('principal-territory =', gettext_cc) print() else: okay.add(language) for language in sorted(primary_languages): if '_' in language: continue cc = ling.parse_language(language).get_principal_territory_code() if cc is None: continue if language not in data: print(f'# WAS: [{language}]') print('# WAS: principal-territory =', cc) print() n_okay = len(okay) print(f'# No principal-territory changes required for {n_okay} languages') print() def do_string_formats(): url = 'https://git.savannah.gnu.org/cgit/gettext.git/plain/gettext-tools/src/message.c' with urllib.request.urlopen(url) as file: contents = file.read() match = re.compile(br'\sformat_language\s*\[NFORMATS\]\s*=\s*[{](.*?)[}]', re.DOTALL).search(contents) if match is None: raise ValueError contents = match.group(1) contents = re.compile(br'/[*].*?[*]/', re.DOTALL).sub(b'', contents) contents = contents.decode('ASCII') their_formats = frozenset( re.findall(r'"([\w-]+)"', contents) ) our_formats = frozenset( gettext.string_formats.keys() ) difference = their_formats ^ our_formats print('[formats]') for fmt in difference: if fmt in our_formats: print(f'# MISSING: {fmt} = ...') else: print(f'{fmt} = # TODO') n_okay = len(our_formats - difference) print(f'# No changes required for {n_okay} string formats') print() def main(): do_plurals() do_languages() do_string_formats() if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/run-pylint0000755000000000000000000000410214275257143017506 0ustar00rootroot00000000000000#!/bin/sh # Copyright © 2015-2019 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON=${PYTHON:-python3} "$PYTHON" -m pylint --version >/dev/null || exit 1 if [ $# -eq 0 ] then pyscripts=$(grep -l -r '^#!.*python' .) set -- lib tests tests/fuzzing/*/*.py $pyscripts fi whitelist= ignored= for ext in afl apt_pkg do if "$PYTHON" -c "import $ext" 2>/dev/null then whitelist="$whitelist,$ext" else ignored="$ignored,$ext" fi done if [ -z "${ignored%%*apt*}" ] then ignored="$ignored,apt" fi set -- --extension-pkg-whitelist="${whitelist#,}" --ignored-modules="${ignored#,}" "$@" log=$(mktemp -t pylint.XXXXXX) "$PYTHON" -m pylint "$@" > "$log" || [ $? != 1 ] ! grep -P '^\S+:' "$log" \ | grep -v -P '^(?!lib/).+: missing-(\w+-)?docstring ' \ | grep -v ": redefined-builtin \\[.*\\] Redefining built-in 'input'" \ | grep -v -P "^tests/.+: wrong-import-order \\[.*\\] external import \"import lib[.].+\" comes before \"from . import tools\"" \ | LC_ALL=C sort -k2 \ | grep '.' || exit 1 rm "$log" # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/tags-as-rst0000755000000000000000000000430214275257143017534 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import io import re import sys sys.path[0] += '/..' from lib import tags as tagmod int(0_0) # Python >= 3.6 is required def output_tags_rst(tags): print('''\ .. This file has been generated automatically by private/tags-as-rst. Do not edit. ''') for tag in tags: tagname = tag.name print(tagname) print('~' * len(tagname)) print(tag.description) print() if tag.references: print('References:', end='\n\n') for ref in tag.references: match = re.match(r'\A(?P[\w-]+)[(](?P
[0-9])[)]\Z', ref) if match is not None: ref = r'**{name}**\ ({section})'.format_map(match.groupdict()) print(' |', ref) print() print('Severity, certainty:', end='\n\n') print(f' {tag.severity.name}, {tag.certainty.name}') print() def main(): sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='UTF-8') output_tags_rst(tagmod.iter_tags()) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-blackbox-tests0000755000000000000000000000331114275257143021573 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2013-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import subprocess as ipc int(0_0) # Python >= 3.6 is required def main(): here = os.path.dirname(__file__) test_dir = f'{here}/../tests/blackbox_tests/' os.chdir(test_dir) for generator in os.listdir('.'): if not generator.endswith('.gen'): continue target = generator[:-4] tmp_target = target + '.tmp' env = dict(os.environ, here='.', target=tmp_target) ipc.check_call(os.path.join('.', generator), env=env) os.rename(tmp_target, target) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-branch-coverage0000755000000000000000000000443014275257143021677 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2014-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import glob import io import os import sys import nose import nose.plugins.cover class Coverage(nose.plugins.cover.Coverage): stream = None def report(self, stream): return super().report(self.stream) basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) def main(): os.chdir(basedir) module_glob = os.path.join('tests', 'test_*.py') modules = glob.glob(module_glob) argv = [ sys.argv[0], '--with-coverage', '--cover-package=lib', '--cover-erase', ] + modules path = os.path.join( 'tests', 'coverage' ) plugin = Coverage() report_stream = plugin.stream = io.StringIO() print('Generated automatically by private/update-branch-coverage. ' 'Do not edit.\n', file=report_stream) ok = nose.run(argv=argv, plugins=[plugin]) if not ok: sys.exit(1) report_stream.seek(0) with open(path + '.tmp', 'wt', encoding='ASCII') as file: for line in report_stream: line = line.rstrip() print(line, file=file) os.rename(path + '.tmp', path) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-charmaps0000755000000000000000000000461514275257143020454 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2013-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools import sys # pylint: disable=wrong-import-position sys.path[0] += '/..' basedir = sys.path[0] from lib import encodings from lib import iconv int(0_0) # Python >= 3.6 is required def generate_charmap(encoding): encoding = encoding.upper() eprint = functools.partial(print, file=sys.stderr, flush=True) eprint(encoding, '...', end=' ') path = f'{basedir}/data/charmaps/{encoding}' n = 0 us = [] for b in range(0x100): b = bytes([b]) try: u = iconv.decode(b, encoding) except UnicodeDecodeError: u = '\uFFFE' else: n += 1 assert len(u) == 1 us += [u] if n <= 128: eprint('SKIP (not 8-bit)') return assert len(us) == 0x100 with open(path, 'wb') as file: us = str.join('', us) assert len(us) == 0x100 file.write(us.encode('UTF-8')) eprint('ok') def main(): # pylint: disable=protected-access for encoding, codec in encodings._portable_encodings.items(): if codec is None: generate_charmap(encoding) for encoding in encodings._extra_encodings: generate_charmap(encoding) # pylint: enable=protected-access if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-header-fields0000755000000000000000000000517514275257143021354 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import subprocess as ipc import tempfile xgettexts = {'xgettext', 'pygettext'} def main(): os.environ['LC_ALL'] = 'C' xgettext_versions = { ipc.check_output([xgettext, '--version']).splitlines()[0].decode('ASCII', 'replace') for xgettext in xgettexts } with tempfile.TemporaryDirectory(prefix='i18nspector.private.') as tmpdir: path = os.path.join(tmpdir, 'dummy.c') with open(path, 'wt', encoding='ASCII') as file: file.write('ngettext("1", "2");') pos = { ipc.check_output([xgettext, '-o', '-', path]) for xgettext in xgettexts } headers = set() for po in pos: po = po.decode('ASCII').splitlines() for line in po: if line.startswith('"'): header = line[1:].split(':', 1)[0] headers.add(header) basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) path = os.path.join(basedir, 'data', 'header-fields') with open(path, 'wt', encoding='ASCII') as file: print('''\ # This file has been generated automatically by # private/update-header-fields. Do not edit. # # The following string extraction tools have been used:\ ''', file=file) for xgettext_version in sorted(xgettext_versions): print('# *', xgettext_version, file=file) print(file=file) for header in sorted(headers): print(header, file=file) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-iso-codes0000755000000000000000000001164614275257143020545 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import datetime import functools import os import subprocess as ipc import sys import json int(0_0) # Python >= 3.6 is required class Panic(ValueError): pass @functools.lru_cache() def get_iso_codes_version(): version = ipc.check_output(['pkg-config', 'iso-codes', '--modversion']) version = version.decode('ASCII').strip() return version @functools.lru_cache() def get_iso_codes_dir(): prefix = ipc.check_output(['pkg-config', 'iso-codes', '--variable=prefix']) prefix = prefix.decode('ASCII').strip() return f'{prefix}/share/iso-codes/json' def main(): basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) path = os.path.join(basedir, 'data', 'iso-codes') sys.stdout = open(path + '.tmp', 'wt', encoding='UTF-8') # pylint: disable=consider-using-with iso_codes_version = get_iso_codes_version() today = datetime.date.today() print(f'''\ # This file has been generated automatically by private/update-iso-codes. # Do not edit. # iso-codes version: {iso_codes_version} # Last update: {today} ''') generate_iso_639() generate_iso_3166() sys.stdout.close() os.rename(path + '.tmp', path) def load_json(path): with open(path, 'rt', encoding='UTF-8') as file: return json.load(file) def generate_iso_639(): # ======================= # ISO 639: language codes # ======================= l2t_to_2b = {} iso_639 = {} data = load_json(get_iso_codes_dir() + '/iso_639-2.json') for item in data['639-2']: l2t = item['alpha_3'] l2b = item.get('bibliographic', l2t) if l2b == l2t == 'qaa-qtz': continue for l in l2b, l2t: if len(l) != 3: raise Panic(f'len({l!r}) != 3') if l2b != l2t: l2t_to_2b[l2t] = l2b iso_639 = {} data = load_json(get_iso_codes_dir() + '/iso_639-3.json') for item in data['639-3']: code = item['alpha_3'] if len(code) != 3: raise Panic(f'len({code!r}) != 3') code1 = item.get('alpha_2') code2 = item.get('terminology') if code2 is None: # We're not interested in languages that are not in 639-2 (yet?). continue if code2 != code: raise Panic(f'{code!r} != {code2!r}') scope = item['scope'] if scope == 'S': # Not a real language, ignore. continue elif scope in {'M', 'I'}: pass else: raise Panic(f'unknown scope: {scope!r}') reference_name = item['name'] if reference_name in iso_639: raise Panic(f'duplicate reference name: {reference_name!r}') if code1 is not None: if len(code1) == 2: codelist = [code1, code] else: raise Panic(f'len({code1!r}) != 2') else: codelist = [code] try: codelist += [l2t_to_2b[code]] except KeyError: pass iso_639[reference_name] = codelist print('[language-codes]') iso_639_rev = {} for code, *aliases in iso_639.values(): for alias in aliases: iso_639_rev[alias] = code if not aliases: iso_639_rev[code] = '' for alias, code in sorted(iso_639_rev.items()): print(f'{alias} = {code}'.rstrip()) print() def generate_iso_3166(): # ========================= # ISO 3166: territory codes # ========================= iso_3166 = set() data = load_json(get_iso_codes_dir() + '/iso_3166-1.json') for item in data['3166-1']: cc = item['alpha_2'] iso_3166.add(cc) print('[territory-codes]') for cc in sorted(iso_3166): print(f'{cc} =') print() print('# vim\72ft=dosini') if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-tag-coverage0000755000000000000000000000403514275257143021216 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys sys.path[0] += '/..' from lib import tags from tests import blackbox_tests int(0_0) # Python >= 3.6 is required def main(): coverage = blackbox_tests.get_coverage() path = os.path.join( os.path.dirname(blackbox_tests.__file__), 'coverage' ) sys.stdout = open(path + '.tmp', 'wt', encoding='ASCII') # pylint: disable=consider-using-with print('Generated automatically by private/update-tag-coverage. ' 'Do not edit.\n') for tag in tags.iter_tags(): check = 'X' if tag.name in coverage else ' ' print(f'[{check}] {tag.name}') sys.stdout.close() os.rename(path + '.tmp', path) rc = 0 for tag in sorted(set(coverage) - {t.name for t in tags.iter_tags()}): print(f'update-coverage: error: unknown tag {tag}', file=sys.stderr) rc = 1 sys.exit(rc) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-timezones0000755000000000000000000000643114275257143020671 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2013-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import collections import datetime import os import subprocess as ipc import sys import pytz # pylint: disable=wrong-import-position sys.path[0] += '/..' basedir = sys.path[0] from lib import gettext int(0_0) # Python >= 3.6 is required def get_tzdata_version(): version = pytz.OLSON_VERSION if os.path.exists('/etc/debian_version'): # On Debian systems, pytz uses the system timezone database, # so pytz.OLSON_VERSION is not reliable. version = ipc.check_output(['dpkg-query', '-Wf', '${Version}', 'tzdata']) version = version.decode('ASCII') version, revision = version.rsplit('-', 1) del revision return version def main(): minyear = gettext.epoch.year maxyear = datetime.date.today().year + 1 tzdata = collections.defaultdict(set) for tzname in pytz.all_timezones: if tzname.startswith('Etc/'): continue tz = pytz.timezone(tzname) try: timestamps = list(tz._utc_transition_times) # pylint: disable=protected-access except AttributeError: timestamps = [] timestamps += [datetime.datetime(minyear, 1, 1)] for timestamp in timestamps: if not (minyear <= timestamp.year <= maxyear): continue timestamp = tz.fromutc(timestamp) code, offset = timestamp.strftime('%Z %z').split() assert 3 <= len(code) <= 6 tzdata[code].add(offset) path = os.path.join(basedir, 'data', 'timezones') sys.stdout = open(path + '.tmp', 'wt', encoding='ASCII') # pylint: disable=consider-using-with tzdata_version = get_tzdata_version() today = datetime.date.today() print(f'''\ # This file has been generated automatically by private/update-timezones. # Do not edit. # Timezone database version: {tzdata_version} # Last update: {today} ''') print('[timezones]') for code, offsets in sorted(tzdata.items()): offsets = str.join(' ', sorted(offsets)) print(f'{code} = {offsets}') print() print('# vim\72ft=dosini') sys.stdout.close() os.rename(path + '.tmp', path) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/private/update-version0000755000000000000000000000040714275257143020336 0ustar00rootroot00000000000000#!/bin/sh version=${1:?"no version number provided"} set -e -x dch -m -v "$version" -u low -c doc/changelog export version perl -pi -e 's/^__version__ = '"'"'\K[\w.]+/$ENV{version}/' lib/*.py perl -pi -e 's/^:version: \S+ \K[\w.]+/$ENV{version}/' doc/manpage.rst i18nspector-0.27.1/pytest.ini0000644000000000000000000000016514275257143016023 0ustar00rootroot00000000000000[pytest] testpaths = tests python_files = test_*.py pytest.py python_classes = test_* python_functions = test test_* i18nspector-0.27.1/tests/0000755000000000000000000000000014275257143015132 5ustar00rootroot00000000000000i18nspector-0.27.1/tests/__init__.py0000644000000000000000000000004614275257143017243 0ustar00rootroot00000000000000int(0_0) # Python >= 3.6 is required i18nspector-0.27.1/tests/blackbox_tests/0000755000000000000000000000000014275257143020141 5ustar00rootroot00000000000000i18nspector-0.27.1/tests/blackbox_tests/__init__.py0000644000000000000000000003042714275257143022260 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import difflib import inspect import io import multiprocessing as mp import os import re import shlex import signal import subprocess as ipc import sys import traceback import unittest from .. import tools here = os.path.dirname(__file__) # ---------------------------------------- def this(): ''' Return function that called this function. (Hopefully!) ''' return globals()[inspect.stack()[1][0].f_code.co_name] # ---------------------------------------- _parse_etag = re.compile(r'([A-Z]): (([\w-]+).*)').match def parse_etag(contents, path): match = _parse_etag(contents) if match is None: return t = ETag(match.group(1), path, match.group(2)) return t def etags_from_tagstring(obj, path): try: docstring = obj.tagstring except AttributeError: return for line in docstring.splitlines(): line = line.lstrip() t = parse_etag(line, path) if t is not None: yield t def tagstring(s): def update(x): x.tagstring = s return x return update # ---------------------------------------- class ETag(): _ellipsis = '<...>' _split = re.compile(f'({re.escape(_ellipsis)})').split def __init__(self, code, path, rest): self._s = s = f'{code}: {path}: {rest}' self.tag = rest.split(None, 1)[0] regexp = str.join('', ( '.*' if chunk == self._ellipsis else re.escape(chunk) for chunk in self._split(s) )) self._regexp = re.compile(f'^{regexp}$') def __eq__(self, other): if isinstance(other, str): return self._regexp.match(other) else: return NotImplemented def __str__(self): return self._s def __repr__(self): return repr(self._s) # ---------------------------------------- def _get_signal_names(): data = { name: getattr(signal, name) for name in dir(signal) if re.compile('^SIG[A-Z0-9]*$').match(name) } try: if data['SIGABRT'] == data['SIGIOT']: del data['SIGIOT'] except KeyError: pass try: if data['SIGCHLD'] == data['SIGCLD']: del data['SIGCLD'] except KeyError: pass for name, n in data.items(): yield n, name _signal_names = dict(_get_signal_names()) def get_signal_name(n): try: return _signal_names[n] except KeyError: return str(n) # ---------------------------------------- test_file_extensions = ('.mo', '.po', '.pot', '.pop') # .pop is a special extension to trigger unknown-file-type def nose_plugin(): import nose.plugins # pylint: disable=import-outside-toplevel class Plugin(nose.plugins.Plugin): name = 'po-plugin' enabled = True def options(self, parser, env): pass def wantFile(self, path): if path.endswith(test_file_extensions): if path.startswith(os.path.join(os.path.abspath(here), '')): return True def loadTestsFromFile(self, path): if self.wantFile(path): yield TestCase(path) def wantFunction(self, func): if getattr(func, 'redundant', False): return False return Plugin() class TestCase(unittest.TestCase): def __init__(self, path): super().__init__('_test') self.path = os.path.relpath(path) def _test(self): _test_file(self.path, basedir=None) def __str__(self): return self.path class SubprocessError(Exception): pass def queue_get(queue, process): ''' Remove and return an item from the queue. Block until the process terminates. ''' while True: try: return queue.get(timeout=1) # This semi-active waiting is ugly, but there doesn't seem be any # obvious better way. except mp.queues.Empty: if process.exitcode is None: continue else: raise def run_i18nspector(options, path): commandline = os.environ.get('I18NSPECTOR_COMMANDLINE') if commandline is None: # We cheat here a bit, because exec(3)ing is very expensive. # Let's load the needed Python modules, and use multiprocessing to # “emulate” the command execution. import lib.cli # pylint: disable=import-outside-toplevel assert lib.cli # make pyflakes happy prog = os.path.join(here, os.pardir, os.pardir, 'i18nspector') commandline = [sys.executable, prog] queue = mp.Queue() child = mp.Process( target=_mp_run_i18nspector, args=(prog, options, path, queue) ) child.start() [stdout, stderr] = ( s.splitlines() for s in queue_get(queue, child) ) child.join() rc = child.exitcode else: commandline = shlex.split(commandline) commandline += options commandline += [path] fixed_env = dict(os.environ, PYTHONIOENCODING='UTF-8') with ipc.Popen(commandline, stdout=ipc.PIPE, stderr=ipc.PIPE, env=fixed_env) as child: stdout, stderr = ( s.decode('UTF-8').splitlines() for s in child.communicate() ) rc = child.poll() assert isinstance(rc, int) if rc == 0: return stdout if rc < 0: message = [f'command was interrupted by signal {get_signal_name(-rc)}'] # pylint: disable=invalid-unary-operand-type else: message = [f'command exited with status {rc}'] message += [''] if stdout: message += ['stdout:'] message += ['| ' + s for s in stdout] + [''] else: message += ['stdout: (empty)'] if stderr: message += ['stderr:'] message += ['| ' + s for s in stderr] else: message += ['stderr: (empty)'] raise SubprocessError(str.join('\n', message)) def _mp_run_i18nspector(prog, options, path, queue): with open(prog, 'rt', encoding='UTF-8') as file: code = file.read() sys.argv = [prog] + list(options) + [path] orig_stdout = sys.stdout orig_stderr = sys.stderr code = compile(code, prog, 'exec') io_stdout = io.StringIO() io_stderr = io.StringIO() gvars = dict( __file__=prog, ) (sys.stdout, sys.stderr) = (io_stdout, io_stderr) stdout = stderr = '' try: try: exec(code, gvars) # pylint: disable=exec-used finally: (sys.stdout, sys.stderr) = (orig_stdout, orig_stderr) stdout = io_stdout.getvalue() stderr = io_stderr.getvalue() except SystemExit: queue.put([stdout, stderr]) raise except: # pylint: disable=bare-except exctp, exc, tb = sys.exc_info() stderr += str.join('', traceback.format_exception(exctp, exc, tb) ) queue.put([stdout, stderr]) sys.exit(1) raise # hi, pydiatra! else: queue.put([stdout, stderr]) sys.exit(0) def assert_emit_tags(path, etags, *, options=()): etags = list(etags) stdout = run_i18nspector(options, path) expected_failure = os.path.basename(path).startswith('xfail-') if stdout != etags: if expected_failure: raise unittest.SkipTest('expected failure') str_etags = [str(x) for x in etags] message = ['Tags differ:', ''] diff = list( difflib.unified_diff(str_etags, stdout, n=9999) ) message += diff[3:] raise AssertionError(str.join('\n', message)) elif expected_failure: raise AssertionError('unexpected success') class TestFileSyntaxError(Exception): pass def _parse_test_header_file(file, path, *, comments_only): etags = [] options = [] for n, line in enumerate(file): orig_line = line if comments_only: if n == 0 and line.startswith('#!'): continue if line.startswith('# '): line = line[2:] else: break if line.startswith('--'): options += shlex.split(line) else: etag = parse_etag(line, path) if etag is None: if comments_only: break else: raise TestFileSyntaxError(orig_line) etags += [etag] return etags, options def _parse_test_headers(path): # .tags: try: file = open(path + '.tags', encoding='UTF-8') # pylint: disable=consider-using-with except FileNotFoundError: pass else: with file: return _parse_test_header_file(file, path, comments_only=False) # .gen: try: file = open(path + '.gen', encoding='UTF-8', errors='ignore') # pylint: disable=consider-using-with except FileNotFoundError: pass else: with file: return _parse_test_header_file(file, path, comments_only=True) # : with open(path, 'rt', encoding='UTF-8', errors='ignore') as file: return _parse_test_header_file(file, path, comments_only=True) def _test_file(path, basedir=here): if basedir is not None: path = os.path.relpath(os.path.join(basedir, path), start=os.getcwd()) options = [] etags, options = _parse_test_headers(path) assert_emit_tags(path, etags, options=options) def get_coverage_for_file(path): etags, options = _parse_test_headers(path) del options return (t.tag for t in etags) def get_coverage_for_function(fn): for etag in etags_from_tagstring(fn, ''): yield etag.tag def _get_test_filenames(): for root, dirnames, filenames in os.walk(here): del dirnames for filename in filenames: if not filename.endswith(test_file_extensions): continue yield os.path.join(root, filename) @tools.collect_yielded def test_file(): for filename in _get_test_filenames(): path = os.path.relpath(filename, start=here) yield _test_file, path test_file.redundant = True # not needed if the plugin is enabled @tagstring(''' E: os-error No such file or directory ''') def test_os_error_no_such_file(): with tools.temporary_directory() as tmpdir: path = os.path.join(tmpdir, 'nonexistent.po') expected = etags_from_tagstring(this(), path) assert_emit_tags(path, expected) @tagstring(''' E: os-error Permission denied ''') def test_os_error_permission_denied(): if os.getuid() == 0: raise unittest.SkipTest('this test must not be run as root') with tools.temporary_directory() as tmpdir: path = os.path.join(tmpdir, 'denied.po') with open(path, 'wb'): pass os.chmod(path, 0) expected = etags_from_tagstring(this(), path) assert_emit_tags(path, expected) # ---------------------------------------- def get_coverage(): coverage = set() for filename in _get_test_filenames(): for tag in get_coverage_for_file(filename): coverage.add(tag) for objname, obj in globals().items(): if not objname.startswith('test_'): continue for tag in get_coverage_for_function(obj): coverage.add(tag) return coverage # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/blackbox_tests/ancient-po-revision-date.po0000644000000000000000000000110214275257143025277 0ustar00rootroot00000000000000# W: ancient-date PO-Revision-Date: '1942-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 1942-04-02 03:37+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/ancient-pot-creation-date.po0000644000000000000000000000110314275257143025432 0ustar00rootroot00000000000000# W: ancient-date POT-Creation-Date: '1942-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 1942-04-02 03:37+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-content-type.po0000644000000000000000000000110714275257143026035 0ustar00rootroot00000000000000# E: boilerplate-in-content-type 'text/plain; charset=CHARSET' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-initial-comments.po0000644000000000000000000000140114275257143026655 0ustar00rootroot00000000000000# Polish translations for PACKAGE package # Polskie tłumaczenia dla pakietu PACKAGE. # Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Jakub Wilk , 2015. # msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-initial-comments.po.tags0000644000000000000000000000042114275257143027613 0ustar00rootroot00000000000000I: boilerplate-in-initial-comments 'Polish translations for PACKAGE package' I: boilerplate-in-initial-comments "Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER" I: boilerplate-in-initial-comments 'This file is distributed under the same license as the PACKAGE package.' i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-initial-comments.pot0000644000000000000000000000123614275257143027047 0ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-initial-comments.pot.tags0000644000000000000000000000030414275257143027777 0ustar00rootroot00000000000000I: boilerplate-in-initial-comments "Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER" I: boilerplate-in-initial-comments 'This file is distributed under the same license as the PACKAGE package.' i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-language-team.po0000644000000000000000000000110214275257143026106 0ustar00rootroot00000000000000# W: boilerplate-in-language-team 'LANGUAGE ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: LANGUAGE \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-last-translator.po0000644000000000000000000000100214275257143026530 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-last-translator.po.tags0000644000000000000000000000007614275257143027477 0ustar00rootroot00000000000000W: boilerplate-in-last-translator 'FULL NAME ' i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-po-revision-date.po0000644000000000000000000000111114275257143026564 0ustar00rootroot00000000000000# W: boilerplate-in-date PO-Revision-Date: 'YEAR-MO-DA HO:MI+ZONE' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-pot-creation-date.po0000644000000000000000000000111214275257143026717 0ustar00rootroot00000000000000# W: boilerplate-in-date POT-Creation-Date: 'YEAR-MO-DA HO:MI+ZONE' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-project-id-version-1.po0000644000000000000000000000107414275257143027270 0ustar00rootroot00000000000000# W: boilerplate-in-project-id-version 'PACKAGE VERSION' msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-project-id-version-2.po0000644000000000000000000000107414275257143027271 0ustar00rootroot00000000000000# W: boilerplate-in-project-id-version 'PROJECT VERSION' msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-report-msgid-bugs.po0000644000000000000000000000100714275257143026755 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/boilerplate-in-report-msgid-bugs.po.tags0000644000000000000000000000010314275257143027706 0ustar00rootroot00000000000000W: boilerplate-in-report-msgid-bugs-to 'FULL NAME ' i18nspector-0.27.1/tests/blackbox_tests/bom-in-translation.po0000644000000000000000000000120414275257143024213 0ustar00rootroot00000000000000# E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+FEFF ZERO WIDTH NO-BREAK SPACE msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/broken-encoding-and-syntax-error.po0000644000000000000000000000120014275257143026751 0ustar00rootroot00000000000000# E: syntax-error-in-po-file line 20 # E: broken-encoding '<...>\xe2\x80\xa6"<...>' cannot be decoded as ASCII msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog..." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" msgid i18nspector-0.27.1/tests/blackbox_tests/broken-encoding-due-to-missing-content-type.po0000644000000000000000000000116414275257143031040 0ustar00rootroot00000000000000# E: broken-encoding '<...>\xe2\x80\xa6"\n' cannot be decoded as ASCII # E: no-content-type-header-field Content-Type: text/plain; charset= msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog..." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" i18nspector-0.27.1/tests/blackbox_tests/broken-encoding.po0000644000000000000000000000112414275257143023543 0ustar00rootroot00000000000000# E: broken-encoding '<...>\xe2\x80\xa6"\n' cannot be decoded as ASCII msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=US-ASCII\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog..." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-argument-mixture.po0000644000000000000000000000123014275257143027024 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': mixed numbered and unnumbered argument specifications '%1$d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %s, zelotypos, quam %1$d haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-argument-range-error.po0000644000000000000000000000121214275257143027552 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': argument index too small or too large '%0$s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %0$s, zelotypos, quam %1$d haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-argument-type-mismatch-1.po0000644000000000000000000000122414275257143030254 0ustar00rootroot00000000000000# E: c-format-string-argument-type-mismatch msgid 'A quick brown %s jumps over the lazy dog.': int (msgstr) != const char * (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %d, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-argument-type-mismatch-2.po0000644000000000000000000000210214275257143030251 0ustar00rootroot00000000000000# E: c-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': short int (msgstr[0]) != int (msgid) # E: c-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': long int (msgstr[2]) != int (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %hd flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %ld flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-argument-type-mismatch.pot0000644000000000000000000000137014275257143030304 0ustar00rootroot00000000000000# E: c-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': int (msgid) != long int (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%ld quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-duplicate-flag.po0000644000000000000000000000120314275257143026370 0ustar00rootroot00000000000000# P: c-format-string-redundant-flag msgid 'A quick brown %--s jumps over the lazy dog.': duplicate - in '%--s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %--s jumps over the lazy dog." msgstr "Sic fugiens, %--s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-error-argument-type-mismatch.po0000644000000000000000000000122114275257143031242 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %1$s jumps over the lazy %1$s.': argument type mismatch 1$ const char *, int msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %1$s jumps over the lazy %1$s." msgstr "Sic fugiens, %1$s, zelotypos, quam %1$d haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-error-missing-argument.po0000644000000000000000000000116014275257143030131 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': missing argument 1$ msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, dux, zelotypos, quam %2$s haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-error.po0000644000000000000000000000120614275257143024643 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid conversion specification '%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-excess-arguments-1.po0000644000000000000000000000117514275257143027152 0ustar00rootroot00000000000000# E: c-format-string-excess-arguments msgid 'A quick brown %s jumps over the lazy dog.': 2 (msgstr) > 1 (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam %s haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-excess-arguments-2.po0000644000000000000000000000204314275257143027146 0ustar00rootroot00000000000000# E: c-format-string-excess-arguments msgid '%d quick brown fox jumps over the lazy dog.': 2 (msgstr[0]) > 1 (msgid) # E: c-format-string-excess-arguments msgid '%d quick brown fox jumps over the lazy dog.': 2 (msgstr[2]) > 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń %2$s twój i %1$d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %1$d flagi." msgstr[2] "Mężny bądź, chroń %2$s twój i %1$d flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-excess-arguments.pot0000644000000000000000000000134414275257143027176 0ustar00rootroot00000000000000# E: c-format-string-excess-arguments msgid '%d quick brown fox jumps over the lazy dog.': 1 (msgid) > 0 (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-flag-error.po0000644000000000000000000000121514275257143025552 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': unexpected format flag character '#' in '%#s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %#s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-forbidden-argument-index.po0000644000000000000000000000122314275257143030372 0ustar00rootroot00000000000000# E: c-format-string-error msgid '100%% of quick brown foxes jump over the lazy %s.': argument index not allowed '%1$%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "100%% of quick brown foxes jump over the lazy %s." msgstr "Mężny bądź, chroń %2$s twój i 100%1$% flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-length-error.po0000644000000000000000000000117514275257143026127 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': invalid length modifier '%hs' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %hs, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-missing-argument.po0000644000000000000000000000116014275257143027002 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': missing argument 1$ msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, dux, zelotypos, quam %2$s haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-missing-non-numeral.po0000644000000000000000000000165114275257143027420 0ustar00rootroot00000000000000# E: c-format-string-missing-arguments msgid '%s quick brown fox jumps over the lazy dog.': 0 (msgstr[0]) < 1 (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%s quick brown fox jumps over the lazy dog." msgid_plural "%s quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %s flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %s flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-missing-non-numeral.pot0000644000000000000000000000134614275257143027605 0ustar00rootroot00000000000000# E: c-format-string-missing-arguments msgid 'A quick brown fox jumps over the lazy dog.': 0 (msgid) < 1 (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-missing-numeral.po0000644000000000000000000000132414275257143026625 0ustar00rootroot00000000000000# E: c-format-string-missing-arguments msgid once: 0 (msgstr[0]) < 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, c-format msgid "once" msgid_plural "%d times" msgstr[0] "paз" msgstr[1] "%d paзи" msgstr[2] "%d paзiв" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-msgid-error.po0000644000000000000000000000102114275257143025737 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-msgid-error.pot0000644000000000000000000000113714275257143026133 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown fox jumps over the lazy dog%': invalid conversion specification '%' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-no-excess-arguments.po0000644000000000000000000000120214275257143027415 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, c-format msgid "once" msgid_plural "%d times" msgstr[0] "%d paз" msgstr[1] "%d paзи" msgstr[2] "%d paзiв" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-non-portable-conversion.po0000644000000000000000000000143314275257143030277 0ustar00rootroot00000000000000# P: c-format-string-non-portable-conversion msgid '%zd%% of quick brown foxes jump over the lazy %S.': '%S' => '%ls' in '%2$S' # P: c-format-string-non-portable-conversion msgid '%zd%% of quick brown foxes jump over the lazy %S.': '%Zd' => '%zd' in '%1$Zd' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "%zd%% of quick brown foxes jump over the lazy %S." msgstr "Mężny bądź, chroń %2$S twój i %1$Zd flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-non-portable-conversion.pot0000644000000000000000000000152714275257143030467 0ustar00rootroot00000000000000# P: c-format-string-non-portable-conversion msgid '%Ld quick brown fox jumps over the lazy dog.': '%Ld' => '%lld' # P: c-format-string-non-portable-conversion msgid '%Ld quick brown fox jumps over the lazy dog.': '%qd' => '%lld' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, c-format msgid "%Ld quick brown fox jumps over the lazy dog." msgid_plural "%qd quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-okay.po0000644000000000000000000000101714275257143024455 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-okay.pot0000644000000000000000000000075114275257143024645 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-omitted-numeral-1.po0000644000000000000000000000146214275257143026762 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-omitted-numeral-2.po0000644000000000000000000000146114275257143026762 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-omitted-numeral-5.po0000644000000000000000000000277214275257143026773 0ustar00rootroot00000000000000# E: c-format-string-missing-arguments msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': 0 (msgstr[2]) < 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # %d doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, c-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # %d cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, c-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-omitted-numeral.pot0000644000000000000000000000115514275257143027007 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-overridden-flag-1.po0000644000000000000000000000123214275257143026717 0ustar00rootroot00000000000000# P: c-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': '+' overridden by ' ' in '%+ d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %+ d%% flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-overridden-flag-2.po0000644000000000000000000000121014275257143026714 0ustar00rootroot00000000000000# P: c-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': 0 in '%0.3d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %0.3d%% flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-plural-okay.po0000644000000000000000000000145514275257143025760 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-plural-okay.pot0000644000000000000000000000115614275257143026142 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-precision-error.po0000644000000000000000000000121214275257143026631 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown fox jumps over the lazy dog%.42s': unexpected precision '%.42c' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog%.42s" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%.42c" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-precision-range-error.po0000644000000000000000000000121514275257143027726 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': precision too large '%.9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %.9999999999s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c-format-string-width-error.po0000644000000000000000000000117614275257143025766 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.%n': unexpected width '%24n' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog.%n" msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis.%24n" i18nspector-0.27.1/tests/blackbox_tests/c-format-string-width-range-error.po0000644000000000000000000000121514275257143027052 0ustar00rootroot00000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': field width too large '%9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %9999999999s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/c0-control-characters.po0000644000000000000000000000120114275257143024570 0ustar00rootroot00000000000000# E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+0019 control character EM msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis" i18nspector-0.27.1/tests/blackbox_tests/c1-control-characters.po0000644000000000000000000000120414275257143024574 0ustar00rootroot00000000000000# E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+0080 control character PAD msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" i18nspector-0.27.1/tests/blackbox_tests/codomain-error-in-plural-forms-1.po0000644000000000000000000000230014275257143026577 0ustar00rootroot00000000000000# E: unusual-plural-forms 'nplurals=5; plural=n==1 ? 1 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' # E: codomain-error-in-plural-forms f(x) != 0 # E: codomain-error-in-plural-forms f(x) != 3, 4 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=5; plural=n==1 ? 1 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." msgstr[3] "Mężny bądź, chroń pułk twój i %d flag." msgstr[4] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/codomain-error-in-plural-forms-1a.po0000644000000000000000000000237114275257143026750 0ustar00rootroot00000000000000# E: unusual-plural-forms 'nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' # E: codomain-error-in-plural-forms f(x) != 3 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." msgstr[3] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/codomain-error-in-plural-forms-2.po0000644000000000000000000000152414275257143026607 0ustar00rootroot00000000000000# E: codomain-error-in-plural-forms f(2) = 7 >= 3 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 7 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/codomain-error-in-unused-plural-forms.po0000644000000000000000000000134114275257143027746 0ustar00rootroot00000000000000# W: codomain-error-in-unused-plural-forms f(x) != 0, 1, 2, ..., 41 # W: codomain-error-in-unused-plural-forms f(x) != 43, 44, 45, ..., 999999999999999999999 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1000000000000000000000; plural=42\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflict-marker-in-fuzzy-translation.po0000644000000000000000000000143314275257143027707 0ustar00rootroot00000000000000# conflict-marker-in-translation should not trigger for fuzzy entries. # https://bugs.debian.org/753924 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" "#-#-#-#-# pl.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.27.1/tests/blackbox_tests/conflict-marker-in-header-entry-1.po0000644000000000000000000000122314275257143026706 0ustar00rootroot00000000000000# E: conflict-marker-in-header-entry '#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflict-marker-in-header-entry-2.po0000644000000000000000000000122314275257143026707 0ustar00rootroot00000000000000# E: conflict-marker-in-header-entry '#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#' msgid "" msgstr "" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflict-marker-in-translation.po0000644000000000000000000000146414275257143026526 0ustar00rootroot00000000000000# E: conflict-marker-in-translation msgid 'A quick brown fox jumps over the lazy dog.' '#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" "#-#-#-#-# pl.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.27.1/tests/blackbox_tests/conflicting-format-flags-1.po0000644000000000000000000000120714275257143025516 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': c-format lisp-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format, lisp-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflicting-format-flags-2.po0000644000000000000000000000120714275257143025517 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': c-format no-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, no-c-format, c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflicting-format-flags-3.po0000644000000000000000000000122714275257143025522 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': c-format impossible-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, impossible-c-format, c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflicting-format-flags-4.po0000644000000000000000000000125114275257143025520 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': possible-c-format impossible-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, possible-c-format, impossible-c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/conflicting-message-flags.po0000644000000000000000000000116714275257143025521 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': wrap no-wrap msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, wrap, no-wrap msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/coverage0000644000000000000000000001024714275257143021663 0ustar00rootroot00000000000000Generated automatically by private/update-tag-coverage. Do not edit. [X] ancient-date [X] arithmetic-error-in-plural-forms [X] arithmetic-error-in-unused-plural-forms [X] boilerplate-in-content-type [X] boilerplate-in-date [X] boilerplate-in-initial-comments [X] boilerplate-in-language-team [X] boilerplate-in-last-translator [X] boilerplate-in-project-id-version [X] boilerplate-in-report-msgid-bugs-to [X] broken-encoding [X] c-format-string-argument-type-mismatch [X] c-format-string-error [X] c-format-string-excess-arguments [X] c-format-string-missing-arguments [X] c-format-string-non-portable-conversion [X] c-format-string-redundant-flag [X] codomain-error-in-plural-forms [X] codomain-error-in-unused-plural-forms [X] conflict-marker-in-header-entry [X] conflict-marker-in-translation [X] conflicting-message-flags [X] date-from-future [X] distant-header-entry [X] duplicate-flag-for-header-entry [X] duplicate-header-entry [X] duplicate-header-field [X] duplicate-header-field-content-transfer-encoding [X] duplicate-header-field-content-type [X] duplicate-header-field-date [X] duplicate-header-field-language [X] duplicate-header-field-language-team [X] duplicate-header-field-last-translator [X] duplicate-header-field-mime-version [X] duplicate-header-field-plural-forms [X] duplicate-header-field-project-id-version [X] duplicate-header-field-report-msgid-bugs-to [X] duplicate-header-field-x-poedit [X] duplicate-message-definition [X] duplicate-message-flag [X] empty-file [X] empty-msgid-message-with-plural-forms [X] empty-msgid-message-with-source-code-references [X] encoding-in-language-header-field [X] fuzzy-header-entry [X] inconsistent-leading-newlines [X] inconsistent-number-of-plural-forms [X] inconsistent-trailing-newlines [X] incorrect-number-of-plural-forms [X] invalid-content-transfer-encoding [X] invalid-content-type [X] invalid-date [X] invalid-language [X] invalid-language-team [X] invalid-last-translator [X] invalid-mime-version [X] invalid-mo-file [X] invalid-range-flag [X] invalid-report-msgid-bugs-to [X] language-disparity [X] language-team-equal-to-last-translator [X] language-variant-does-not-affect-translation [X] leading-junk-in-plural-forms [X] malformed-xml [X] no-content-transfer-encoding-header-field [X] no-content-type-header-field [X] no-date-header-field [X] no-language-header-field [X] no-language-team-header-field [X] no-last-translator-header-field [X] no-mime-version-header-field [X] no-package-name-in-project-id-version [X] no-plural-forms-header-field [X] no-project-id-version-header-field [X] no-report-msgid-bugs-to-header-field [X] no-required-plural-forms-header-field [X] no-version-in-project-id-version [X] non-ascii-compatible-encoding [X] non-portable-encoding [X] os-error [X] partially-translated-message [X] perl-brace-format-string-error [X] perl-brace-format-string-missing-argument [X] perl-brace-format-string-unknown-argument [X] python-brace-format-string-argument-type-mismatch [X] python-brace-format-string-error [X] python-brace-format-string-missing-argument [X] python-brace-format-string-unknown-argument [X] python-format-string-argument-number-mismatch [X] python-format-string-argument-type-mismatch [X] python-format-string-error [X] python-format-string-missing-argument [X] python-format-string-multiple-unnamed-arguments [X] python-format-string-obsolete-conversion [X] python-format-string-redundant-flag [X] python-format-string-redundant-length [X] python-format-string-redundant-precision [X] python-format-string-unknown-argument [X] python-format-string-unnamed-plural-argument [X] qt-plural-format-mistaken-for-c-format [X] range-flag-without-plural-string [X] redundant-message-flag [X] stray-header-line [X] stray-previous-msgid [X] syntax-error-in-plural-forms [X] syntax-error-in-po-file [X] syntax-error-in-unused-plural-forms [X] trailing-junk-in-plural-forms [X] translation-in-template [X] unable-to-determine-language [X] unexpected-flag-for-header-entry [X] unknown-encoding [X] unknown-file-type [X] unknown-header-field [X] unknown-message-flag [X] unknown-poedit-language [X] unrepresentable-characters [X] unusual-character-in-header-entry [X] unusual-character-in-translation [X] unusual-plural-forms [X] unusual-unused-plural-forms i18nspector-0.27.1/tests/blackbox_tests/crlf.po0000644000000000000000000000102414275257143021424 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/distant-header-entry.po0000644000000000000000000000104014275257143024527 0ustar00rootroot00000000000000# E: distant-header-entry msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" i18nspector-0.27.1/tests/blackbox_tests/dotless-domain-in-language-team.po0000644000000000000000000000105714275257143026537 0ustar00rootroot00000000000000# W: invalid-language-team 'Latin ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/dotless-domain-in-last-translator.po0000644000000000000000000000106614275257143027162 0ustar00rootroot00000000000000# W: invalid-last-translator 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/dotless-domain-in-report-msgid-bugs-to.po0000644000000000000000000000106614275257143030022 0ustar00rootroot00000000000000# W: invalid-report-msgid-bugs-to 'gizmoenhancer@net' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-empty-flag.po0000644000000000000000000000116414275257143024520 0ustar00rootroot00000000000000# I: unknown-message-flag msgid 'A quick brown fox jumps over the lazy dog.': (empty string) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, ,no-c-format, msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-flag-for-header-entry.pot0000644000000000000000000000102114275257143026711 0ustar00rootroot00000000000000# W: duplicate-flag-for-header-entry fuzzy #, fuzzy, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-entry.po0000644000000000000000000000167214275257143025046 0ustar00rootroot00000000000000# E: duplicate-header-entry msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-content-transfer-encoding.po0000644000000000000000000000114014275257143032034 0ustar00rootroot00000000000000# P: duplicate-header-field-content-transfer-encoding msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-content-type.po0000644000000000000000000000113314275257143027407 0ustar00rootroot00000000000000# E: duplicate-header-field-content-type msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-language-team.po0000644000000000000000000000112514275257143027466 0ustar00rootroot00000000000000# W: duplicate-header-field-language-team msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-language.po0000644000000000000000000000107414275257143026545 0ustar00rootroot00000000000000# E: duplicate-header-field-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-last-translator.po0000644000000000000000000000114414275257143030112 0ustar00rootroot00000000000000# W: duplicate-header-field-last-translator msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-mime-version.po0000644000000000000000000000110514275257143027367 0ustar00rootroot00000000000000# P: duplicate-header-field-mime-version msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-plural-forms.po0000644000000000000000000000166214275257143027410 0ustar00rootroot00000000000000# E: duplicate-header-field-plural-forms msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-po-revision-date.po0000644000000000000000000000114414275257143030145 0ustar00rootroot00000000000000# W: duplicate-header-field-date PO-Revision-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-pot-creation-date.po0000644000000000000000000000114614275257143030301 0ustar00rootroot00000000000000# W: duplicate-header-field-date POT-Creation-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-project-id-version.po0000644000000000000000000000114014275257143030477 0ustar00rootroot00000000000000# W: duplicate-header-field-project-id-version msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-report-msgid-bugs-to.po0000644000000000000000000000115114275257143030750 0ustar00rootroot00000000000000# W: duplicate-header-field-report-msgid-bugs-to msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-x-poedit-country.po0000644000000000000000000000116614275257143030216 0ustar00rootroot00000000000000# W: duplicate-header-field-x-poedit X-Poedit-Country msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Country: Poland\n" "X-Poedit-Country: Poland\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field-x-poedit-language.po0000644000000000000000000000116714275257143030277 0ustar00rootroot00000000000000# W: duplicate-header-field-x-poedit X-Poedit-Language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Latin\n" "X-Poedit-Language: Latin\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-header-field.po0000644000000000000000000000114314275257143024761 0ustar00rootroot00000000000000# I: duplicate-header-field Generated-By msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: VIM 7.3\n" "Generated-By: VIM 7.3\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-message-definition-with-context.po0000644000000000000000000000136714275257143030665 0ustar00rootroot00000000000000# E: duplicate-message-definition msgid 'A quick brown fox jumps over the lazy dog.' msgctxt rot13 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgctxt "rot13" msgid "A quick brown fox jumps over the lazy dog." msgstr "Fvp shtvraf, qhk, mrybglcbf, dhnz Xnehf unorevf." msgctxt "rot13" msgid "A quick brown fox jumps over the lazy dog." msgstr "Fvp shtvraf, qhk, mrybglcbf, dhnz Xnehf unorevf." i18nspector-0.27.1/tests/blackbox_tests/duplicate-message-definition.po0000644000000000000000000000131114275257143026217 0ustar00rootroot00000000000000# E: duplicate-message-definition msgid 'A quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/duplicate-message-flag.po0000644000000000000000000000117614275257143025011 0ustar00rootroot00000000000000# W: duplicate-message-flag msgid 'A quick brown fox jumps over the lazy dog.': no-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, no-c-format, no-c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-content-transfer-encoding.po0000644000000000000000000000110014275257143026705 0ustar00rootroot00000000000000# P: invalid-content-transfer-encoding (empty string) => 8bit msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-content-type.po0000644000000000000000000000107214275257143024266 0ustar00rootroot00000000000000# E: invalid-content-type (empty string) => 'text/plain; charset=' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: \n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-file.po0000644000000000000000000000065114275257143022556 0ustar00rootroot00000000000000# W: empty-file msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" i18nspector-0.27.1/tests/blackbox_tests/empty-file.pot0000644000000000000000000000066114275257143022743 0ustar00rootroot00000000000000# W: empty-file #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" i18nspector-0.27.1/tests/blackbox_tests/empty-mime-version.po0000644000000000000000000000106314275257143024247 0ustar00rootroot00000000000000# P: invalid-mime-version (empty string) => 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: \n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-msgid-message-with-plural-forms.po0000644000000000000000000000157214275257143027761 0ustar00rootroot00000000000000# E: empty-msgid-message-with-plural-forms msgid "" msgid_plural "" msgstr[0] "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgstr[1] "" msgstr[2] "" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/empty-msgid-message-with-source-code-references.po0000644000000000000000000000112414275257143031656 0ustar00rootroot00000000000000# E: empty-msgid-message-with-source-code-references 'gizmo.c:1' #: gizmo.c:1 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-po-revision-date.po0000644000000000000000000000104414275257143025021 0ustar00rootroot00000000000000# W: invalid-date PO-Revision-Date: (empty string) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: \n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-pot-creation-date.po0000644000000000000000000000104514275257143025154 0ustar00rootroot00000000000000# W: invalid-date POT-Creation-Date: (empty string) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: \n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-project-id-version.po0000644000000000000000000000114314275257143025357 0ustar00rootroot00000000000000# I: no-package-name-in-project-id-version (empty string) # P: no-version-in-project-id-version (empty string) msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/empty-report-msgid-bugs.po0000644000000000000000000000103114275257143025202 0ustar00rootroot00000000000000# W: no-report-msgid-bugs-to-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/encoding-in-header-field.po0000644000000000000000000000107414275257143025204 0ustar00rootroot00000000000000# W: encoding-in-language-header-field la.UTF-8 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la.UTF-8\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/escape-sequences.po0000644000000000000000000000115214275257143023731 0ustar00rootroot00000000000000# E: duplicate-message-definition msgid '\x07\x07\x08\x08\x0c\x0c\t\t\x0b\x0b\r…\n' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "\a\7\b\x8\f\x0c\t\11\v\013\r\xE2\x80\246\n" msgstr "" msgid "\a\7\b\x8\f\x0c\t\11\v\013\r\342\200\xA6\n" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/future-po-revision-date.po0000644000000000000000000000110614275257143025174 0ustar00rootroot00000000000000# W: date-from-future PO-Revision-Date: '2142-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2142-04-02 03:37+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/future-pot-creation-date.po0000644000000000000000000000110714275257143025327 0ustar00rootroot00000000000000# W: date-from-future POT-Creation-Date: '2142-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2142-04-02 03:37+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/fuzzy-header-entry.po0000644000000000000000000000104714275257143024257 0ustar00rootroot00000000000000# P: fuzzy-header-entry #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/generated-by-field.po0000644000000000000000000000162014275257143024127 0ustar00rootroot00000000000000# The Generated-By field is not used or generated by any of the GNU # gettext tools. Nevertheless it's rather widespread, as it's used by # pygettext[0] and Babel[1]. Emitting unknown-header-field would be # counter-productive. # # [0] https://docs.python.org/3/library/gettext.html#internationalizing-your-programs-and-modules # [1] https://babel.pocoo.org/ msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/hash-only-comment.po0000644000000000000000000000101414275257143024037 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #oops msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/header-entry-flags-splitting.po0000644000000000000000000000114514275257143026176 0ustar00rootroot00000000000000# P: fuzzy-header-entry # W: unexpected-flag-for-header-entry no-c-format #, no-c-format,fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/header-imitation.mo0000644000000000000000000000034714275257143023725 0ustar00rootroot00000000000000,<P*c'0(header imitation)A quick brown fox jumps over the lazy dog.Content-Type: text/plain; charset=UTF-8Sic fugiens, dux, zelotypos, quam Karus haberisi18nspector-0.27.1/tests/blackbox_tests/header-imitation.mo.gen0000755000000000000000000000116614275257143024500 0ustar00rootroot00000000000000#!/bin/sh # E: broken-encoding '<...>' cannot be decoded as ASCII # P: no-language-header-field # I: unable-to-determine-language # P: no-mime-version-header-field MIME-Version: 1.0 # P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit # E: no-content-type-header-field Content-Type: text/plain; charset= # W: no-date-header-field PO-Revision-Date # W: no-project-id-version-header-field # W: no-report-msgid-bugs-to-header-field # W: no-last-translator-header-field # P: no-language-team-header-field set -e -u -x exec msgfmt --endian=little "${here}/xfail-header-imitation.po" -o "${target}" i18nspector-0.27.1/tests/blackbox_tests/inconsistent-leading-newlines-fuzzy.po0000644000000000000000000000102014275257143027622 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy msgid "\nA quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/inconsistent-leading-newlines.po0000644000000000000000000000114014275257143026440 0ustar00rootroot00000000000000# E: inconsistent-leading-newlines msgid '\nA quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "\nA quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/inconsistent-leading-newlines.pot0000644000000000000000000000127614275257143026636 0ustar00rootroot00000000000000# E: inconsistent-leading-newlines msgid '\n%d quick brown fox jumps over the lazy dog.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" msgid "\n%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/inconsistent-number-of-plural-forms.po0000644000000000000000000000234214275257143027533 0ustar00rootroot00000000000000# E: inconsistent-number-of-plural-forms 2 (msgid '%d quick brown fox jumps over the lazy dog.' msgctxt 'missing plural form') != 3 (msgid '%d quick brown fox jumps over the lazy dog.') msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." msgctxt "missing plural form" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." i18nspector-0.27.1/tests/blackbox_tests/inconsistent-trailing-newlines-fuzzy.po0000644000000000000000000000102014275257143030030 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" i18nspector-0.27.1/tests/blackbox_tests/inconsistent-trailing-newlines.po0000644000000000000000000000113714275257143026654 0ustar00rootroot00000000000000# E: inconsistent-trailing-newlines msgid 'A quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" i18nspector-0.27.1/tests/blackbox_tests/inconsistent-trailing-newlines.pot0000644000000000000000000000127514275257143027043 0ustar00rootroot00000000000000# E: inconsistent-trailing-newlines msgid '%d quick brown fox jumps over the lazy dog.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog.\n" msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/incorrect-plural-forms.po0000644000000000000000000000147714275257143025123 0ustar00rootroot00000000000000# E: unusual-plural-forms 'nplurals=2; plural=n != 1;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." i18nspector-0.27.1/tests/blackbox_tests/integer-overflow-in-plural-forms.po0000644000000000000000000000154414275257143027030 0ustar00rootroot00000000000000# E: arithmetic-error-in-plural-forms f(12): integer overflow msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%(0-100)>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/integer-overflow-in-unused-plural-forms.po0000644000000000000000000000126614275257143030332 0ustar00rootroot00000000000000# W: arithmetic-error-in-unused-plural-forms f(12): integer overflow msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%(0-100)>=20) ? 1 : 2;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-content-transfer-encoding.po0000644000000000000000000000107414275257143027207 0ustar00rootroot00000000000000# P: invalid-content-transfer-encoding 42bit => 8bit msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 42bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-content-type-with-hint.po0000644000000000000000000000114114275257143026464 0ustar00rootroot00000000000000# E: invalid-content-type 'text/enriched; charset=UTF-8' => 'text/plain; charset=UTF-8' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/enriched; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-content-type.po0000644000000000000000000000110214275257143024550 0ustar00rootroot00000000000000# E: invalid-content-type 'text/plain' => 'text/plain; charset=' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-language-corrected.po0000644000000000000000000000104714275257143025662 0ustar00rootroot00000000000000# E: invalid-language lat => la msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: lat\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-language-natural-name.po0000644000000000000000000000105314275257143026271 0ustar00rootroot00000000000000# E: invalid-language Latin => la msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: Latin\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-language.po0000644000000000000000000000110114275257143023701 0ustar00rootroot00000000000000# E: invalid-language LA # I: unable-to-determine-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: LA\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-last-translator.po0000644000000000000000000000103614275257143025257 0ustar00rootroot00000000000000# W: invalid-last-translator 'Jakub Wilk' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk\n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-mime-version.po0000644000000000000000000000105314275257143024536 0ustar00rootroot00000000000000# P: invalid-mime-version 4.2 => 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 4.2\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-mo-file.mo0000644000000000000000000000107114275257143023451 0ustar00rootroot00000000000000# E: invalid-mo-file unexpected magic msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." # vim:ft=po i18nspector-0.27.1/tests/blackbox_tests/invalid-po-revision-date-with-hint.po0000644000000000000000000000113714275257143027225 0ustar00rootroot00000000000000# W: invalid-date PO-Revision-Date: '2012-11-01 14:42+01:00' => '2012-11-01 14:42+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+01:00\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-po-revision-date.po0000644000000000000000000000105214275257143025310 0ustar00rootroot00000000000000# W: invalid-date PO-Revision-Date: 2012-11-01 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-pot-creation-date-with-hint.po0000644000000000000000000000114014275257143027351 0ustar00rootroot00000000000000# W: invalid-date POT-Creation-Date: '2012-11-01 14:42+01:00' => '2012-11-01 14:42+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+01:00\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-pot-creation-date.po0000644000000000000000000000105314275257143025443 0ustar00rootroot00000000000000# W: invalid-date POT-Creation-Date: 2012-11-01 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/invalid-range-flag-1-element.po0000644000000000000000000000161414275257143025717 0ustar00rootroot00000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..1' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..1 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/invalid-range-flag-empty.po0000644000000000000000000000161414275257143025266 0ustar00rootroot00000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 2..1' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 2..1 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/invalid-range-flag-trailing-junk.po0000644000000000000000000000161614275257143026710 0ustar00rootroot00000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..5x' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5x msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/invalid-range-flag.po0000644000000000000000000000161214275257143024130 0ustar00rootroot00000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1-5' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1-5 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/invalid-report-msgid-bugs.po0000644000000000000000000000112214275257143025473 0ustar00rootroot00000000000000# W: invalid-report-msgid-bugs-to 'Gizmo Enhancer Development Team' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: Gizmo Enhancer Development Team\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/language-disparity-command-line.po0000644000000000000000000000113614275257143026634 0ustar00rootroot00000000000000# --language el # W: language-disparity el (command-line) != la (Language header field) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/language-disparity-poedit.po0000644000000000000000000000117514275257143025560 0ustar00rootroot00000000000000# W: language-disparity la (Language header field) != el (X-Poedit-Language header field) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Greek\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/language-team-equal-to-last-translator-2.po0000644000000000000000000000131714275257143030226 0ustar00rootroot00000000000000# W: duplicate-header-field-last-translator # I: language-team-equal-to-last-translator 'Latin ' 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/language-team-equal-to-last-translator.po0000644000000000000000000000116114275257143030064 0ustar00rootroot00000000000000# I: language-team-equal-to-last-translator 'Latin ' 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/language-variant-does-affect-translation.po0000644000000000000000000000101214275257143030432 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la@quot\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/language-variant-does-not-affect-translation.po0000644000000000000000000000110714275257143031235 0ustar00rootroot00000000000000# I: language-variant-does-not-affect-translation 'la@euro' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la@euro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/leading-junk-in-plural-forms.po0000644000000000000000000000154314275257143026101 0ustar00rootroot00000000000000# E: leading-junk-in-plural-forms 'Plural-Forms: ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/lexer-error-in-plural-expression.po0000644000000000000000000000176314275257143027054 0ustar00rootroot00000000000000# E: syntax-error-in-plural-forms 'nplurals=3; plural=n==1 ? 0 : n%10>=2 & n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 & n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/lowercase-header-field-name.po0000644000000000000000000000116114275257143025711 0ustar00rootroot00000000000000# I: unknown-header-field Mime-Version => MIME-Version # P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "Mime-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/markdown-text.po0000644000000000000000000000103614275257143023305 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, markdown-text msgid "A quick brown **fox** jumps over the lazy dog." msgstr "Sic fugiens, **dux**, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/message-flags-splitting-1.po0000644000000000000000000000103414275257143025366 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, no-c-format,fuzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" i18nspector-0.27.1/tests/blackbox_tests/message-flags-splitting-2.po0000644000000000000000000000102114275257143025363 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" i18nspector-0.27.1/tests/blackbox_tests/multiple-range-flags-1.po0000644000000000000000000000163714275257143024665 0ustar00rootroot00000000000000# W: duplicate-message-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..05' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5, range: 1..05 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/multiple-range-flags-2.po0000644000000000000000000000166214275257143024664 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..5' 'range: 37..42' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5, range: 37..42 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/multiple-range-flags-3.po0000644000000000000000000000167714275257143024673 0ustar00rootroot00000000000000# E: conflicting-message-flags msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..5' 'range: 37..42' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5, range: 37..42, range: 1..5 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/next-line-control-character-in-header-entry.po0000644000000000000000000000112014275257143030777 0ustar00rootroot00000000000000# E: unusual-character-in-header-entry U+0085 control character NEL msgid "" msgstr "" "Project-Id-Version: Gizmo Enhąncer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/next-line-control-character-in-translation.po0000644000000000000000000000122014275257143030747 0ustar00rootroot00000000000000# E: unrepresentable-characters ISO-8859-1 <...> # E: unusual-character-in-translation <...>, U+0085 control character NEL, <...> msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.27.1/tests/blackbox_tests/no-content-transfer-encoding.po0000644000000000000000000000106114275257143026171 0ustar00rootroot00000000000000# P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-content-type.po0000644000000000000000000000105114275257143023541 0ustar00rootroot00000000000000# E: no-content-type-header-field Content-Type: text/plain; charset= msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-language-header-field-with-hint.po0000644000000000000000000000106014275257143027113 0ustar00rootroot00000000000000# --language=la # P: no-language-header-field Language: la msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-language-header-field.po0000644000000000000000000000106514275257143025207 0ustar00rootroot00000000000000# P: no-language-header-field # I: unable-to-determine-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-language-team.po0000644000000000000000000000100414275257143023615 0ustar00rootroot00000000000000# P: no-language-team-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-last-translator.po0000644000000000000000000000077114275257143024252 0ustar00rootroot00000000000000# W: no-last-translator-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-mime-version.po0000644000000000000000000000104414275257143023524 0ustar00rootroot00000000000000# P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-package-name-in-project-id-version.po0000644000000000000000000000104614275257143027552 0ustar00rootroot00000000000000# I: no-package-name-in-project-id-version 1.0 msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-plural-forms.po0000644000000000000000000000125214275257143023536 0ustar00rootroot00000000000000# W: no-plural-forms-header-field 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" msgstr[2] "" i18nspector-0.27.1/tests/blackbox_tests/no-plural-forms.pot0000644000000000000000000000116514275257143023725 0ustar00rootroot00000000000000# W: no-plural-forms-header-field 'nplurals=INTEGER; plural=EXPRESSION;' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/no-po-revision-date.po0000644000000000000000000000100514275257143024274 0ustar00rootroot00000000000000# W: no-date-header-field PO-Revision-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-pot-creation-date.po0000644000000000000000000000100514275257143024426 0ustar00rootroot00000000000000# W: no-date-header-field POT-Creation-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-project-id-version.po0000644000000000000000000000100314275257143024630 0ustar00rootroot00000000000000# W: no-project-id-version-header-field msgid "" msgstr "" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-report-msgid-bugs.po0000644000000000000000000000077614275257143024477 0ustar00rootroot00000000000000# W: no-report-msgid-bugs-to-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/no-required-plural-forms.po0000644000000000000000000000147514275257143025363 0ustar00rootroot00000000000000# E: no-required-plural-forms-header-field 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/no-version-in-project-id-version.po0000644000000000000000000000107114275257143026724 0ustar00rootroot00000000000000# P: no-version-in-project-id-version 'Gizmo Enhancer' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/non-ascii-compatible.po0000644000000000000000000000105714275257143024501 0ustar00rootroot00000000000000# E: non-ascii-compatible-encoding UTF-7 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-7\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/non-ascii-project-id.po0000644000000000000000000000102214275257143024412 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Гизмо Энханцэр 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/non-portable-encoding-with-hint.po0000644000000000000000000000107714275257143026603 0ustar00rootroot00000000000000# E: non-portable-encoding Windows-1252 => CP1252 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=Windows-1252\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/non-portable-encoding.po0000644000000000000000000000106314275257143024665 0ustar00rootroot00000000000000# E: non-portable-encoding ISO-8859-16 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-16\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/non-python-encoding.po0000644000000000000000000000111314275257143024372 0ustar00rootroot00000000000000# E: non-portable-encoding KOI8-RU msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=KOI8-RU\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr " Ʀ ަ, Τ ' ." i18nspector-0.27.1/tests/blackbox_tests/non-python-portable-encoding.po0000644000000000000000000000075514275257143026213 0ustar00rootroot00000000000000# E: non-portable-encoding GEORGIAN-PS msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Georgian \n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=GEORGIAN-PS\n" "Content-Transfer-Encoding: 8bit\n" msgid "Georgia" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/non-text-encoding.po0000644000000000000000000000105414275257143024041 0ustar00rootroot00000000000000# E: unknown-encoding zlib_codec msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=zlib_codec\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/nonexistent-language.po0000644000000000000000000000110114275257143024631 0ustar00rootroot00000000000000# E: invalid-language ry # I: unable-to-determine-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: ry\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/okay-big-endian.mo0000644000000000000000000000074114275257143023436 0ustar00rootroot00000000000000,<P*Q3|0A quick brown fox jumps over the lazy dog.Project-Id-Version: Gizmo Enhancer 1.0 Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net PO-Revision-Date: 2012-11-01 14:42+0100 Last-Translator: Jakub Wilk Language-Team: Latin Language: la MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sic fugiens, dux, zelotypos, quam Karus haberis.i18nspector-0.27.1/tests/blackbox_tests/okay-big-endian.mo.gen0000755000000000000000000000016614275257143024212 0ustar00rootroot00000000000000#!/bin/sh set -e -u -x exec grep -v '^"POT-Creation-Date: ' "${here}/okay.po"\ | msgfmt --endian=big - -o "${target}" i18nspector-0.27.1/tests/blackbox_tests/okay-little-endian.mo0000644000000000000000000000074114275257143024172 0ustar00rootroot00000000000000,<P*Q3|0A quick brown fox jumps over the lazy dog.Project-Id-Version: Gizmo Enhancer 1.0 Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net PO-Revision-Date: 2012-11-01 14:42+0100 Last-Translator: Jakub Wilk Language-Team: Latin Language: la MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sic fugiens, dux, zelotypos, quam Karus haberis.i18nspector-0.27.1/tests/blackbox_tests/okay-little-endian.mo.gen0000755000000000000000000000017114275257143024742 0ustar00rootroot00000000000000#!/bin/sh set -e -u -x exec grep -v '^"POT-Creation-Date: ' "${here}/okay.po"\ | msgfmt --endian=little - -o "${target}" i18nspector-0.27.1/tests/blackbox_tests/okay.po0000644000000000000000000000100514275257143021440 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/okay.pot0000644000000000000000000000073614275257143021636 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/partially-translated-message.po0000644000000000000000000000151314275257143026263 0ustar00rootroot00000000000000# E: partially-translated-message msgid '%d quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-error.po0000644000000000000000000000123114275257143026433 0ustar00rootroot00000000000000# E: perl-brace-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid placeholder specification '{' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis{" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-missing-argument.po0000644000000000000000000000123114275257143030573 0ustar00rootroot00000000000000# E: perl-brace-format-string-missing-argument msgid 'A quick brown {A} jumps over the lazy {B}': A not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown {A} jumps over the lazy {B}" msgstr "Sic fugiens, dux, zelotypos, quam {B} haberis." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-missing-arguments.pot0000644000000000000000000000161014275257143031143 0ustar00rootroot00000000000000# E: perl-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.': N not in msgid while in msgid_plural # E: perl-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.': X not in msgid while in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, perl-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy {X}." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-missing-numeral.po0000644000000000000000000000136014275257143030417 0ustar00rootroot00000000000000# E: perl-brace-format-string-missing-argument msgid once: N not in msgstr[0] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, perl-brace-format msgid "once" msgid_plural "{N} times" msgstr[0] "paз" msgstr[1] "{N} paзи" msgstr[2] "{N} paзiв" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-msgid-error.po0000644000000000000000000000103214275257143027533 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown fox jumps over the lazy dog{" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis{" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-msgid-error.pot0000644000000000000000000000116214275257143027723 0ustar00rootroot00000000000000# E: perl-brace-format-string-error msgid 'A quick brown fox jumps over the lazy dog{': invalid placeholder specification '{' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown fox jumps over the lazy dog{" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-no-excess-arguments.po0000644000000000000000000000121714275257143031215 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, perl-brace-format msgid "once" msgid_plural "{N} times" msgstr[0] "{N} paз" msgstr[1] "{N} paзи" msgstr[2] "{N} paзiв" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-okay.po0000644000000000000000000000103214275257143026244 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown {X} jumps over the lazy dog." msgstr "Sic fugiens, {X}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-okay.pot0000644000000000000000000000076314275257143026442 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown {X} jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-omitted-numeral-1.po0000644000000000000000000000147714275257143030562 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, perl-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-omitted-numeral-2.po0000644000000000000000000000147514275257143030561 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, perl-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-omitted-numeral-5.po0000644000000000000000000000304214275257143030554 0ustar00rootroot00000000000000# E: perl-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': N not in msgstr[2] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # {N} doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, perl-brace-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # {N} cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, perl-brace-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-omitted-numeral.pot0000644000000000000000000000116714275257143030604 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, perl-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-plural-okay.po0000644000000000000000000000147314275257143027552 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, perl-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i {N} flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-plural-okay.pot0000644000000000000000000000117114275257143027731 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, perl-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-unknown-argument-1.po0000644000000000000000000000123114275257143030757 0ustar00rootroot00000000000000# E: perl-brace-format-string-unknown-argument msgid 'A quick brown {A} jumps over the lazy dog.': B in msgstr but not in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, perl-brace-format msgid "A quick brown {A} jumps over the lazy dog." msgstr "Sic fugiens, {A}, zelotypos, quam {B} haberis." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-unknown-argument-2.po0000644000000000000000000000211114275257143030756 0ustar00rootroot00000000000000# E: perl-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': O in msgstr[0] but not in msgid # E: perl-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': O in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, perl-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń {O} twój i {N} flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń {O} twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/perl-brace-format-string-unknown-argument.pot0000644000000000000000000000137614275257143031017 0ustar00rootroot00000000000000# E: perl-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': N in msgid but not in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, perl-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/plural-forms-okay.po0000644000000000000000000000144114275257143024065 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/plural-forms-okay.pot0000644000000000000000000000114214275257143024247 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/plural-forms-without-plural-expression.po0000644000000000000000000000151514275257143030321 0ustar00rootroot00000000000000# E: syntax-error-in-plural-forms 3 => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: 3\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/po4a-xml-malformed.po0000644000000000000000000000127214275257143024110 0ustar00rootroot00000000000000# E: malformed-xml msgid 'A quick brown fox jumps over the lazy dog.': asynchronous entity: line 1, column 54 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Content of: msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/po4a-xml-malformed.pot0000644000000000000000000000121114275257143024265 0ustar00rootroot00000000000000# E: malformed-xml msgid 'A quick brown fox jumps over the lazy dog.': asynchronous entity: line 1, column 48 #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Content of: msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/po4a-xml.po0000644000000000000000000000110514275257143022137 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Content of: msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/previous-msgid.po0000644000000000000000000000110614275257143023454 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy #| msgid "The quick brown fox jumps over the lazy dog." msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/publican-dates.po0000644000000000000000000000141614275257143023376 0ustar00rootroot00000000000000# E: invalid-content-type 'application/x-publican; charset=UTF-8' => 'text/plain; charset=UTF-8' # W: invalid-date POT-Creation-Date: '2012-11-01T13:42' => '2012-11-01 13:42-0000' # W: invalid-date PO-Revision-Date: '2012-11-01T13:42' => '2012-11-01 13:42-0000' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01T13:42\n" "PO-Revision-Date: 2012-11-01T13:42\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: application/x-publican; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/pytest.py0000644000000000000000000000266014275257143022047 0ustar00rootroot00000000000000# Copyright © 2021 Jakub Wilk # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # pytest wouldn't look for tests in the __init__.py, # so let's expose the tests through a separate module. from . import ( test_file, test_os_error_no_such_file, test_os_error_permission_denied, ) __all__ = [ 'test_file', 'test_os_error_no_such_file', 'test_os_error_permission_denied', ] # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-index-too-large.po0000644000000000000000000000124614275257143032505 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': argument index too large '{9999999999}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {9999999999}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-mixture.po0000644000000000000000000000125414275257143031203 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy {}.': mixed numbered and unnumbered argument specifications '{1}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy {}." msgstr "Sic fugiens, {}, zelotypos, quam {1} haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-number-mismatch-1.po0000644000000000000000000000163514275257143032742 0ustar00rootroot00000000000000# E: python-brace-format-string-unknown-argument msgid 'A quick brown {} jumps over the lazy dog.': 1 in msgstr but not in msgid # E: python-brace-format-string-missing-argument msgid 'A quick brown {} jumps over the lazy {}.': 1 not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {}, zelotypos, quam {} haberis." #, python-brace-format msgid "A quick brown {} jumps over the lazy {}." msgstr "Sic fugiens, {}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-number-mismatch-2.po0000644000000000000000000000171514275257143032742 0ustar00rootroot00000000000000# E: python-brace-format-string-unknown-argument msgid '{} quick brown fox jumps over the lazy dog.': 1 in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{} quick brown fox jumps over the lazy dog." msgid_plural "{} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {:{}} flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-sorting.po0000644000000000000000000000102614275257143031170 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy {s}." msgstr "Sic fugiens, {}, zelotypos, quam Karus {s}." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-type-mismatch.po0000644000000000000000000000124714275257143032274 0ustar00rootroot00000000000000# E: python-brace-format-string-argument-type-mismatch msgid 'A quick brown {:s} jumps over the lazy dog.': int (msgstr) != str (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {:s} jumps over the lazy dog." msgstr "Sic fugiens, {:d}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-argument-type-mismatch.pot0000644000000000000000000000141614275257143032456 0ustar00rootroot00000000000000# E: python-brace-format-string-argument-type-mismatch msgid '{:s} quick brown fox jumps over the lazy dog.': str (msgid) != int (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-brace-format msgid "{:s} quick brown fox jumps over the lazy dog." msgid_plural "{:d} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-error-argument-type-mismatch.po0000644000000000000000000000131514275257143033417 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {O:s} jumps over the lazy {O:s}.': argument type mismatch 'Sic fugiens, {O:s}, zelotypos, quam {O:d} haberis.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {O:s} jumps over the lazy {O:s}." msgstr "Sic fugiens, {O:s}, zelotypos, quam {O:d} haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-error.po0000644000000000000000000000124314275257143027015 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid replacement field specification '}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis}" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-invalid-conversion-flag.po0000644000000000000000000000122514275257143032404 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': invalid conversion flag '{!z}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {!z}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-mismatched-conversion-flag.po0000644000000000000000000000127414275257143033100 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': type mismatch between conversion and format specifications '{!s:d}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {!s:d}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-missing-argument.po0000644000000000000000000000224214275257143031155 0ustar00rootroot00000000000000# E: python-brace-format-string-missing-argument msgid 'A quick brown {} jumps over the lazy {}': 1 not in msgstr while in msgid # E: python-brace-format-string-missing-argument msgid 'A quick brown {0} jumps over the lazy {1}': 0 not in msgstr while in msgid # E: python-brace-format-string-missing-argument msgid 'A quick brown {A} jumps over the lazy {B}': A not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy {}" msgstr "Sic fugiens, dux, zelotypos, quam {} haberis." #, python-brace-format msgid "A quick brown {0} jumps over the lazy {1}" msgstr "Sic fugiens, dux, zelotypos, quam {1} haberis." #, python-brace-format msgid "A quick brown {A} jumps over the lazy {B}" msgstr "Sic fugiens, dux, zelotypos, quam {B} haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-missing-non-numeral.po0000644000000000000000000000172514275257143031573 0ustar00rootroot00000000000000# E: python-brace-format-string-missing-argument msgid '{N:s} quick brown fox jumps over the lazy dog.': N not in msgstr[0] while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N:s} quick brown fox jumps over the lazy dog." msgid_plural "{N:s} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N:s} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N:s} flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-missing-non-numeral.pot0000644000000000000000000000140614275257143031753 0ustar00rootroot00000000000000# E: python-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.': N not in msgid while in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N:s} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-missing-numeral.po0000644000000000000000000000136414275257143031002 0ustar00rootroot00000000000000# E: python-brace-format-string-missing-argument msgid once: N not in msgstr[0] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-brace-format msgid "once" msgid_plural "{N} times" msgstr[0] "paз" msgstr[1] "{N} paзи" msgstr[2] "{N} paзiв" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-msgid-error.po0000644000000000000000000000103414275257143030114 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog}" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis}" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-msgid-error.pot0000644000000000000000000000117414275257143030305 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown fox jumps over the lazy dog}': invalid replacement field specification '}' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog}" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-no-excess-arguments.po0000644000000000000000000000122114275257143031567 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-brace-format msgid "once" msgid_plural "{N} times" msgstr[0] "{N} paз" msgstr[1] "{N} paзи" msgstr[2] "{N} paзiв" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-okay.po0000644000000000000000000000103214275257143026623 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-okay.pot0000644000000000000000000000076414275257143027022 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-omitted-numeral-1.po0000644000000000000000000000150114275257143031125 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-omitted-numeral-2.po0000644000000000000000000000147714275257143031142 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-omitted-numeral-5.po0000644000000000000000000000305014275257143031132 0ustar00rootroot00000000000000# E: python-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': N not in msgstr[2] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # {N} doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, python-brace-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # {N} cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, python-brace-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-omitted-numeral.pot0000644000000000000000000000117114275257143031156 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-plural-okay.po0000644000000000000000000000147514275257143030133 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i {N} flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-plural-okay.pot0000644000000000000000000000117314275257143030312 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-precision-range-error.po0000644000000000000000000000125614275257143032104 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': invalid format specification '{:.9999999999}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {:.9999999999}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-unknown-argument-1.po0000644000000000000000000000123514275257143031342 0ustar00rootroot00000000000000# E: python-brace-format-string-unknown-argument msgid 'A quick brown {A} jumps over the lazy dog.': B in msgstr but not in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {A} jumps over the lazy dog." msgstr "Sic fugiens, {A}, zelotypos, quam {B} haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-unknown-argument-2.po0000644000000000000000000000211714275257143031343 0ustar00rootroot00000000000000# E: python-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': O in msgstr[0] but not in msgid # E: python-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': O in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń {O} twój i {N} flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń {O} twój i {N} flag." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-unknown-argument.pot0000644000000000000000000000140214275257143031364 0ustar00rootroot00000000000000# E: python-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': N in msgid but not in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-valid-conversion-flag.po0000644000000000000000000000103414275257143032053 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {!s}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-brace-format-string-width-range-error.po0000644000000000000000000000125414275257143031226 0ustar00rootroot00000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': invalid format specification '{:9999999999}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {:9999999999}, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-mixture.po0000644000000000000000000000123614275257143030131 0ustar00rootroot00000000000000# E: python-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': mixed named and unnamed argument specifications '%(n)d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %s, zelotypos, quam %(n)d haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-number-mismatch-1.po0000644000000000000000000000161114275257143031662 0ustar00rootroot00000000000000# E: python-format-string-argument-number-mismatch msgid 'A quick brown %s jumps over the lazy dog.': 2 (msgstr) != 1 (msgid) # E: python-format-string-argument-number-mismatch msgid 'A quick brown %s jumps over the lazy %s.': 1 (msgstr) != 2 (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam %s haberis." #, python-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-number-mismatch-2.po0000644000000000000000000000210514275257143031662 0ustar00rootroot00000000000000# E: python-format-string-argument-number-mismatch msgid '%d quick brown fox jumps over the lazy dog.': 0 (msgstr[0]) != 1 (msgid) # E: python-format-string-argument-number-mismatch msgid '%d quick brown fox jumps over the lazy dog.': 2 (msgstr[2]) != 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %*d flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-number-mismatch.pot0000644000000000000000000000234214275257143031712 0ustar00rootroot00000000000000# I: python-format-string-unnamed-plural-argument msgid '%d quick brown fox jumps over the lazy dog.' # E: python-format-string-argument-number-mismatch msgid '%d quick brown fox jumps over the lazy dog.': 1 (msgid) != 0 (msgid_plural) # I: python-format-string-unnamed-plural-argument msgid 'A quick brown fox jumps over the lazy dog.' # E: python-format-string-argument-number-mismatch msgid 'A quick brown fox jumps over the lazy dog.': 0 (msgid) != 1 (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-type-mismatch-1.po0000644000000000000000000000163314275257143031357 0ustar00rootroot00000000000000# E: python-format-string-argument-type-mismatch msgid 'A quick brown %s jumps over the lazy dog.': int (msgstr) != str (msgid) # E: python-format-string-argument-type-mismatch msgid 'A quick brown %(O)s jumps over the lazy dog.': int (msgstr) != str (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %d, zelotypos, quam Karus haberis." #, python-format msgid "A quick brown %(O)s jumps over the lazy dog." msgstr "Sic fugiens, %(O)d, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-type-mismatch-2.po0000644000000000000000000000324314275257143031357 0ustar00rootroot00000000000000# E: python-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': str (msgstr[0]) != int (msgid) # E: python-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': object (msgstr[2]) != int (msgid_plural) # E: python-format-string-argument-type-mismatch msgid '%(N)d quick brown fox jumps over the lazy dog.': str (msgstr[0]) != int (msgid) # E: python-format-string-argument-type-mismatch msgid '%(N)d quick brown fox jumps over the lazy dog.': object (msgstr[2]) != int (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %s flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %r flag." #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %(N)s flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)r flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-argument-type-mismatch.pot0000644000000000000000000000221714275257143031404 0ustar00rootroot00000000000000# I: python-format-string-unnamed-plural-argument msgid '%d quick brown fox jumps over the lazy dog.' # E: python-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': int (msgid) != str (msgid_plural) # E: python-format-string-argument-type-mismatch msgid '%(N)d quick brown fox jumps over the lazy dog.': int (msgid) != str (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-duplicate-flag.po0000644000000000000000000000121514275257143027472 0ustar00rootroot00000000000000# P: python-format-string-redundant-flag msgid 'A quick brown %--s jumps over the lazy dog.': duplicate - in '%--s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %--s jumps over the lazy dog." msgstr "Sic fugiens, %--s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-error-argument-type-mismatch.po0000644000000000000000000000122714275257143032347 0ustar00rootroot00000000000000# E: python-format-string-error msgid 'A quick brown %(O)s jumps over the lazy %(O)s.': argument type mismatch O int, str msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %(O)s jumps over the lazy %(O)s." msgstr "Sic fugiens, %(O)s, zelotypos, quam %(O)d haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-error.po0000644000000000000000000000122014275257143025736 0ustar00rootroot00000000000000# E: python-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid conversion specification '%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-forbidden-argument-key.po0000644000000000000000000000124414275257143031155 0ustar00rootroot00000000000000# E: python-format-string-error msgid '100%% of quick brown foxes jump over the lazy %(O)s.': argument key not allowed '%(P)%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "100%% of quick brown foxes jump over the lazy %(O)s." msgstr "Mężny bądź, chroń %(O)s twój i 100%(P)% flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-missing-argument.po0000644000000000000000000000123514275257143030104 0ustar00rootroot00000000000000# E: python-format-string-missing-argument msgid 'A quick brown %(A)s jumps over the lazy %(B)s.': A not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %(A)s jumps over the lazy %(B)s." msgstr "Sic fugiens, dux, zelotypos, quam %(B)s haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-missing-non-numeral.po0000644000000000000000000000171114275257143030514 0ustar00rootroot00000000000000# E: python-format-string-missing-argument msgid '%(N)s quick brown fox jumps over the lazy dog.': N not in msgstr[0] while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)s quick brown fox jumps over the lazy dog." msgid_plural "%(N)s quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)s flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)s flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-missing-non-numeral.pot0000644000000000000000000000137214275257143030703 0ustar00rootroot00000000000000# E: python-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.': N not in msgid while in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-missing-numeral.po0000644000000000000000000000135614275257143027731 0ustar00rootroot00000000000000# E: python-format-string-missing-argument msgid once: N not in msgstr[0] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-format msgid "once" msgid_plural "%(N)d times" msgstr[0] "paз" msgstr[1] "%(N)d paзи" msgstr[2] "%(N)d paзiв" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-msgid-error.po0000644000000000000000000000102614275257143027043 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-msgid-error.pot0000644000000000000000000000115114275257143027226 0ustar00rootroot00000000000000# E: python-format-string-error msgid 'A quick brown fox jumps over the lazy dog%': invalid conversion specification '%' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-multiple-unnamed-arguments.pot0000644000000000000000000000112414275257143032257 0ustar00rootroot00000000000000# E: python-format-string-multiple-unnamed-arguments msgid 'A quick brown %s jumps over the lazy %s.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy %s." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-no-excess-arguments.po0000644000000000000000000000120714275257143030521 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-format msgid "once" msgid_plural "%d times" msgstr[0] "%d paз" msgstr[1] "%d paзи" msgstr[2] "%d paзiв" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-obsolete-conversion.po0000644000000000000000000000121014275257143030603 0ustar00rootroot00000000000000# P: python-format-string-obsolete-conversion msgid '%d quick brown foxes jump over the lazy dog.': '%u' => '%d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%d quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %u flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-obsolete-conversion.pot0000644000000000000000000000114314275257143030774 0ustar00rootroot00000000000000# P: python-format-string-obsolete-conversion msgid '%u quick brown foxes jump over the lazy dog.': '%u' => '%d' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%u quick brown foxes jump over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-okay.po0000644000000000000000000000102414275257143025552 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-okay.pot0000644000000000000000000000075614275257143025751 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-omitted-numeral-1.po0000644000000000000000000000150314275257143030055 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)d flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-omitted-numeral-2.po0000644000000000000000000000147714275257143030070 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)d flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-omitted-numeral-5.po0000644000000000000000000000304214275257143030061 0ustar00rootroot00000000000000# E: python-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': N not in msgstr[2] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # %(N)d doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, python-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # %(N)d cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, python-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-omitted-numeral.pot0000644000000000000000000000116514275257143030107 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-overridden-flag-1.po0000644000000000000000000000124414275257143030021 0ustar00rootroot00000000000000# P: python-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': '+' overridden by ' ' in '%+ d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %+ d%% flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-overridden-flag-2.po0000644000000000000000000000122214275257143030016 0ustar00rootroot00000000000000# P: python-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': 0 in '%0.3d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %0.3d%% flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-plural-okay.po0000644000000000000000000000150114275257143027047 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %(N)d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)d flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-plural-okay.pot0000644000000000000000000000117114275257143027236 0ustar00rootroot00000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-precision-range-error.po0000644000000000000000000000122714275257143031030 0ustar00rootroot00000000000000# E: python-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': precision too large '%.9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %.9999999999s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-redundant-flag.po0000644000000000000000000000117714275257143027513 0ustar00rootroot00000000000000# P: python-format-string-redundant-flag msgid 'A quick brown %s jumps over the lazy dog.': '#' in '%#s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %#s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-redundant-flag.pot0000644000000000000000000000113014275257143027664 0ustar00rootroot00000000000000# P: python-format-string-redundant-flag msgid 'A quick brown %0s jumps over the lazy dog.': 0 in '%0s' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %0s jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-redundant-length.po0000644000000000000000000000117714275257143030063 0ustar00rootroot00000000000000# P: python-format-string-redundant-length msgid 'A quick brown %s jumps over the lazy dog.': h in '%hs' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %hs, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-redundant-length.pot0000644000000000000000000000113214275257143030236 0ustar00rootroot00000000000000# P: python-format-string-redundant-length msgid 'A quick brown %ls jumps over the lazy dog.': l in '%ls' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %ls jumps over the lazy dog." msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-redundant-precision.po0000644000000000000000000000122314275257143030565 0ustar00rootroot00000000000000# P: python-format-string-redundant-precision msgid 'A quick brown fox jumps over the lazy dog%.42c': 42 in '%.42c' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%.42c" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%.42c" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-redundant-precision.pot0000644000000000000000000000115014275257143030750 0ustar00rootroot00000000000000# P: python-format-string-redundant-precision msgid 'A quick brown fox jumps over the lazy dog%.42c': 42 in '%.42c' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%.42c" msgstr "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-unknown-argument-1.po0000644000000000000000000000123114275257143030264 0ustar00rootroot00000000000000# E: python-format-string-unknown-argument msgid 'A quick brown %(A)s jumps over the lazy dog.': B in msgstr but not in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %(A)s jumps over the lazy dog." msgstr "Sic fugiens, %(A)s, zelotypos, quam %(B)s haberis." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-unknown-argument-2.po0000644000000000000000000000211714275257143030271 0ustar00rootroot00000000000000# E: python-format-string-unknown-argument msgid '%(N)d quick brown fox jumps over the lazy dog.': O in msgstr[0] but not in msgid # E: python-format-string-unknown-argument msgid '%(N)d quick brown fox jumps over the lazy dog.': O in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń %(O)s twój i %(N)d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń %(O)s twój i %(N)d flag." i18nspector-0.27.1/tests/blackbox_tests/python-format-string-unknown-argument.pot0000644000000000000000000000137214275257143030320 0ustar00rootroot00000000000000# E: python-format-string-unknown-argument msgid '%(N)d quick brown fox jumps over the lazy dog.': N in msgid but not in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.27.1/tests/blackbox_tests/python-format-string-width-range-error.po0000644000000000000000000000122714275257143030154 0ustar00rootroot00000000000000# E: python-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': field width too large '%9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %9999999999s, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/qt-plural-format-mistaken-for-c-format.po0000644000000000000000000000161614275257143030017 0ustar00rootroot00000000000000# E: qt-plural-format-mistaken-for-c-format msgid '%n quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%n quick brown fox jumps over the lazy dog." msgid_plural "%n quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %n flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %n flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %n flag." i18nspector-0.27.1/tests/blackbox_tests/range-flag-without-plural-string.po0000644000000000000000000000107314275257143027007 0ustar00rootroot00000000000000# W: range-flag-without-plural-string msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, range: 1..5 msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/redundant-message-flag.po0000644000000000000000000000123514275257143025017 0ustar00rootroot00000000000000# P: redundant-message-flag msgid 'A quick brown fox jumps over the lazy dog.': possible-c-format (implied by c-format) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format, possible-c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/rfc2606-in-language-team.po0000644000000000000000000000107714275257143024707 0ustar00rootroot00000000000000# W: invalid-language-team 'Latin ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/rfc2606-in-last-translator.po0000644000000000000000000000110614275257143025323 0ustar00rootroot00000000000000# W: invalid-last-translator 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/rfc2606-in-report-msgid-bugs-to.po0000644000000000000000000000110614275257143026163 0ustar00rootroot00000000000000# W: invalid-report-msgid-bugs-to 'gizmoenhancer@example.org' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@example.org\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/seemingly-duplicate-message-definition.po0000644000000000000000000000120314275257143030211 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." msgctxt "rot13" msgid "A quick brown fox jumps over the lazy dog." msgstr "Fvp shtvraf, qhk, mrybglcbf, dhnz Xnehf unorevf." i18nspector-0.27.1/tests/blackbox_tests/stray-header-line-1.po0000644000000000000000000000114314275257143024153 0ustar00rootroot00000000000000# E: stray-header-line 'MIME-Version 1.0' # P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/stray-header-line-2.po0000644000000000000000000000116214275257143024155 0ustar00rootroot00000000000000# E: stray-header-line 'POT-Creation-Date 2012-11-01 14:42+0100' # W: no-date-header-field POT-Creation-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/stray-header-line-3.po0000644000000000000000000000115414275257143024157 0ustar00rootroot00000000000000# E: stray-header-line 'Project-Id-Version Gizmo Enhancer 1.0' # W: no-project-id-version-header-field msgid "" msgstr "" "Project-Id-Version Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/stray-previous-msgid.po0000644000000000000000000000121314275257143024613 0ustar00rootroot00000000000000# W: stray-previous-msgid msgid 'A quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #| msgid "The quick brown fox jumps over the lazy dog." msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/syntax-error-in-plural-expression.po0000644000000000000000000000176314275257143027263 0ustar00rootroot00000000000000# E: syntax-error-in-plural-forms 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/syntax-error-in-unused-plural-expression.po0000644000000000000000000000151014275257143030552 0ustar00rootroot00000000000000# E: syntax-error-in-unused-plural-forms 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.27.1/tests/blackbox_tests/syntax-error.po0000644000000000000000000000077014275257143023162 0ustar00rootroot00000000000000# E: syntax-error-in-po-file line 16 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/trailing-comment.po0000644000000000000000000000101514275257143023747 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." # oops i18nspector-0.27.1/tests/blackbox_tests/trailing-junk-in-plural-forms.po0000644000000000000000000000151014275257143026301 0ustar00rootroot00000000000000# E: trailing-junk-in-plural-forms > msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;>\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/translation-in-template.pot0000644000000000000000000000113714275257143025442 0ustar00rootroot00000000000000# W: translation-in-template msgid 'A quick brown fox jumps over the lazy dog.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/typoed-flag-for-header-entry.po0000644000000000000000000000110414275257143026061 0ustar00rootroot00000000000000# W: unexpected-flag-for-header-entry muzzy => fuzzy #, muzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/typoed-header-field-name.po0000644000000000000000000000116114275257143025231 0ustar00rootroot00000000000000# I: unknown-header-field MIME-Wersion => MIME-Version # P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Wersion: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unexpected-flag-for-header-entry.po0000644000000000000000000000107514275257143026730 0ustar00rootroot00000000000000# W: unexpected-flag-for-header-entry blurry #, blurry msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-encoding.po0000644000000000000000000000104414275257143023763 0ustar00rootroot00000000000000# E: unknown-encoding UTF-42 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-42\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-file-type.pop0000644000000000000000000000105214275257143024252 0ustar00rootroot00000000000000# I: unknown-file-type msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." # vim:ft=po i18nspector-0.27.1/tests/blackbox_tests/unknown-format-flag.po0000644000000000000000000000116714275257143024402 0ustar00rootroot00000000000000# I: unknown-message-flag msgid 'A quick brown fox jumps over the lazy dog.': intercal-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, intercal-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-header-field-no-duplicate-hint.po0000644000000000000000000000126314275257143030033 0ustar00rootroot00000000000000# I: unknown-header-field POT-Revision-Date # Don't suggest renaming a field if such rename would lead to field # duplication. msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "POT-Revision-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-header-field.po0000644000000000000000000000111214275257143024502 0ustar00rootroot00000000000000# I: unknown-header-field Generator msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generator: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-message-flag.po0000644000000000000000000000114314275257143024530 0ustar00rootroot00000000000000# I: unknown-message-flag msgid 'A quick brown fox jumps over the lazy dog.': muzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, muzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-poedit-language.po0000644000000000000000000000110414275257143025237 0ustar00rootroot00000000000000# I: unknown-poedit-language Latn msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Latn\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-x-header-field-1.po0000644000000000000000000000104714275257143025114 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unknown-x-header-field-2.po0000644000000000000000000000104714275257143025115 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "x-generator: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/blackbox_tests/unrepresentable-characters-euro.po0000644000000000000000000000135714275257143026772 0ustar00rootroot00000000000000# I: language-variant-does-not-affect-translation 'pl@euro' # E: unrepresentable-characters ISO-8859-1 <...> # E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+00BF INVERTED QUESTION MARK msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl@euro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mny bd, chro puk twj i sze flag." i18nspector-0.27.1/tests/blackbox_tests/unrepresentable-characters.po0000644000000000000000000000125614275257143026020 0ustar00rootroot00000000000000# E: unrepresentable-characters ISO-8859-1 <...> # E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+00BF INVERTED QUESTION MARK msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mny bd, chro puk twj i sze flag." i18nspector-0.27.1/tests/blackbox_tests/unusual-character-in-plural-translation.po0000644000000000000000000000162414275257143030367 0ustar00rootroot00000000000000# E: unusual-character-in-translation msgid '%d quick brown fox jumps over the lazy dog.': U+FFFF non-character msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag￿" i18nspector-0.27.1/tests/blackbox_tests/unusual-number-of-plural-forms.po0000644000000000000000000000151214275257143026505 0ustar00rootroot00000000000000# E: incorrect-number-of-plural-forms 3 (Plural-Forms header field) != 2 (number of msgstr items) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." i18nspector-0.27.1/tests/blackbox_tests/unusual-unused-plural-forms.po0000644000000000000000000000131614275257143026120 0ustar00rootroot00000000000000# W: unusual-unused-plural-forms 'nplurals=2; plural=n != 1;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.27.1/tests/blackbox_tests/valid-range-flag.po0000644000000000000000000000146014275257143023602 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/xfail-header-imitation.po0000644000000000000000000000153414275257143025030 0ustar00rootroot00000000000000# E: broken-encoding '<...>' cannot be decoded as ASCII # P: no-language-header-field # I: unable-to-determine-language # P: no-mime-version-header-field MIME-Version: 1.0 # P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit # E: no-content-type-header-field Content-Type: text/plain; charset= # W: no-date-header-field POT-Creation-Date # W: no-date-header-field PO-Revision-Date # W: no-project-id-version-header-field # W: no-report-msgid-bugs-to-header-field # W: no-last-translator-header-field # P: no-language-team-header-field # This msgid should sort first asciibetically, # so that the entry ends up first in the MO file, too. msgid "(header imitation)" msgstr "Content-Type: text/plain; charset=UTF-8" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis" i18nspector-0.27.1/tests/blackbox_tests/xfail-partially-translated-message-2.po0000644000000000000000000000157014275257143027526 0ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # msgstr[2] doesn't have to be translated, because (according to the range # flag) it will never be used. #, c-format, range: 1..4 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "" i18nspector-0.27.1/tests/blackbox_tests/zero-bytes-file.mo0000644000000000000000000000000014275257143023504 0ustar00rootroot00000000000000i18nspector-0.27.1/tests/blackbox_tests/zero-bytes-file.mo.tags0000644000000000000000000000004414275257143024451 0ustar00rootroot00000000000000E: invalid-mo-file unexpected magic i18nspector-0.27.1/tests/blackbox_tests/zero-bytes-file.po0000644000000000000000000000000014275257143023507 0ustar00rootroot00000000000000i18nspector-0.27.1/tests/blackbox_tests/zero-bytes-file.po.tags0000644000000000000000000000077314275257143024465 0ustar00rootroot00000000000000P: no-language-header-field I: unable-to-determine-language P: no-mime-version-header-field MIME-Version: 1.0 P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit E: no-content-type-header-field Content-Type: text/plain; charset= W: no-date-header-field POT-Creation-Date W: no-date-header-field PO-Revision-Date W: no-project-id-version-header-field W: no-report-msgid-bugs-to-header-field W: no-last-translator-header-field P: no-language-team-header-field W: empty-file i18nspector-0.27.1/tests/blackbox_tests/zero-division-error-in-plural-forms.po0000644000000000000000000000153614275257143027463 0ustar00rootroot00000000000000# E: arithmetic-error-in-plural-forms f(2): division by zero msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%0<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.27.1/tests/blackbox_tests/zero-division-error-in-unused-plural-forms.po0000644000000000000000000000126014275257143030756 0ustar00rootroot00000000000000# W: arithmetic-error-in-unused-plural-forms f(2): division by zero msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%0<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.27.1/tests/conftest.py0000644000000000000000000000746614275257143017346 0ustar00rootroot00000000000000# encoding=UTF-8 # Copyright © 2021 Stuart Prescott # Copyright © 2021-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import inspect import os import unittest import pytest import tests.tools int(0_0) # Python >= 3.6 is required def _make_method(fn, args): def _test_item(self): del self return fn(*args) return _test_item def _make_skip_func(exc): def test(self=None): raise exc return test if int(pytest.__version__.split('.', 1)[0]) < 6: # pytest before 6.0 doesn't like "[" in the test name # https://github.com/pytest-dev/pytest/commit/8b9b81c3c04399d0 def _mangle_test_name(s): return s.replace('[', '(').replace(']', ')') else: _mangle_test_name = str def _collect_yielded(generator): genargs = list(inspect.signature(generator).parameters.keys()) if genargs == ['self']: class YieldTestDescriptor(): def __set_name__(self, owner, name): try: args_lst = list(generator(owner())) except unittest.SkipTest as exc: skip_method = _make_skip_func(exc) setattr(owner, name, skip_method) return for args in args_lst: fn, *args = args aname = name + repr(args) aname = _mangle_test_name(aname) assert getattr(owner, aname, None) is None setattr(owner, aname, _make_method(fn, args)) return YieldTestDescriptor() elif genargs == []: # pylint: disable=use-implicit-booleaness-not-comparison class Test(): pass try: args_lst = list(generator()) except unittest.SkipTest as exc: return _make_skip_func(exc) for args in args_lst: fn, *args = args aname = 'test' + repr(args) aname = _mangle_test_name(aname) assert getattr(Test, aname , None) is None setattr(Test, aname, _make_method(fn, args)) Test.__module__ = generator.__module__ Test.__name__ = generator.__name__ Test.__qualname__ = generator.__qualname__ return Test else: raise RuntimeError def pytest_sessionstart(session): envvar = 'XDG_CACHE_HOME' old_xdg_cache_home = os.environ.get(envvar, None) xdg_temp_dir = tests.tools.temporary_directory() # pylint: disable=consider-using-with os.environ[envvar] = xdg_temp_dir.name def cleanup(): xdg_temp_dir.cleanup() if old_xdg_cache_home is None: del os.environ[envvar] else: os.environ[envvar] = old_xdg_cache_home session.config.add_cleanup(cleanup) tests.tools.collect_yielded = _collect_yielded # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/coverage0000644000000000000000000000601714275257143016654 0ustar00rootroot00000000000000Generated automatically by private/update-branch-coverage. Do not edit. Name Stmts Miss Branch BrPart Cover Missing ------------------------------------------------------------------------------ lib/__init__.py 1 0 0 0 100% lib/check/__init__.py 811 750 505 0 5% 83-87, 90-103, 118-203, 206-222, 226-358, 362-506, 510-582, 586-629, 634-669, 674-718, 721-799, 802-882, 885-1006, 1009-1016, 1019-1035, 1040 lib/check/msgformat/__init__.py 84 68 38 0 15% 31, 39, 42-152 lib/check/msgformat/c.py 67 56 38 0 12% 37-44, 47-105, 108-129 lib/check/msgformat/perlbrace.py 28 19 8 0 31% 37-48, 51-65 lib/check/msgformat/pybrace.py 35 26 15 0 22% 37-48, 51-75 lib/check/msgformat/python.py 77 67 49 0 10% 37-109, 112-149 lib/check/msgrepr.py 11 7 2 0 31% 28-34 lib/cli.py 163 127 54 0 18% 44-48, 57-66, 69-70, 73-75, 81-110, 113-118, 124-130, 133-141, 144-149, 152-157, 163, 172-190, 193-199, 202-236 lib/domains.py 16 0 0 0 100% lib/encodings.py 134 35 38 2 75% 50-66, 78-86, 134->144, 195, 209-222, 226-230 lib/gettext.py 105 0 38 0 100% lib/iconv.py 158 48 52 18 64% 41-42, 55-57, 64, 66, 68, 70, 83-84, 97-98, 105->110, 111-123, 130-131, 134-145, 151, 153, 155, 157, 166-167, 180-181, 203-204, 213, 222, 226-237 lib/intexpr.py 420 0 140 0 100% lib/ling.py 244 2 100 3 99% 159->162, 181, 277->283, 281 lib/misc.py 42 0 18 0 100% lib/moparser.py 138 92 60 3 30% 56->58, 68, 76, 91-109, 112-178, 183-192, 195 lib/paths.py 7 2 0 0 71% 36-37 lib/polib4us.py 118 74 30 0 32% 40-41, 55, 71, 74-94, 98, 108-110, 131-143, 147, 159, 168-173, 184-192, 203, 206, 210-214, 226-233, 241-250 lib/strformat/__init__.py 0 0 0 0 100% lib/strformat/c.py 285 0 206 0 100% lib/strformat/perlbrace.py 27 0 12 0 100% lib/strformat/pybrace.py 156 0 94 0 100% lib/strformat/python.py 206 0 124 0 100% lib/tags.py 117 28 36 3 77% 82, 84, 87, 106-107, 118-120, 125-127, 151-158, 164-169, 180-187, 206, 212 lib/terminal.py 48 17 10 1 62% 37-38, 64, 80-93 lib/xml.py 21 0 2 0 100% ------------------------------------------------------------------------------ TOTAL 3519 1418 1669 30 57% i18nspector-0.27.1/tests/fuzzing/0000755000000000000000000000000014275257143016626 5ustar00rootroot00000000000000i18nspector-0.27.1/tests/fuzzing/mo-parser/0000755000000000000000000000000014275257143020533 5ustar00rootroot00000000000000i18nspector-0.27.1/tests/fuzzing/mo-parser/run0000755000000000000000000000271014275257143021265 0ustar00rootroot00000000000000#!/bin/sh # Copyright © 2015-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -e here=$(dirname "$0") output="$here/output" if [ -e "$output/" ] then input=- else input=$(mktemp -d -t i18nspector.fuzzing.XXXXXX) cp "$here/../../blackbox_tests/"*.mo "$input/" fi export AFL_FAST_CAL=1 exec py-afl-fuzz -m 100 -i "$input" -o "$output" -T i18nspector-mo-parser -- python3 "$here/test.py" # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/fuzzing/mo-parser/test.py0000644000000000000000000000403014275257143022061 0ustar00rootroot00000000000000# Copyright © 2015-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import encodings import importlib import os import pkgutil import sys import afl sys.path[0] += '/../../..' import tests.tools import lib.moparser as M temporary_file = tests.tools.temporary_file def parser_for_bytes(data): with temporary_file(suffix='.mo') as file: file.write(data) file.flush() return M.Parser(file.name) def test(data): try: parser_for_bytes(data) except M.SyntaxError: return except UnicodeDecodeError: pass def main(): for _, modname, _ in pkgutil.iter_modules(encodings.__path__, prefix='encodings.'): try: importlib.import_module(modname) except (LookupError, ImportError): pass while afl.loop(max=1000): data = sys.stdin.buffer.read() # pylint: disable=no-member test(data) os._exit(0) # pylint: disable=protected-access if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/fuzzing/plural-forms/0000755000000000000000000000000014275257143021251 5ustar00rootroot00000000000000i18nspector-0.27.1/tests/fuzzing/plural-forms/input/0000755000000000000000000000000014275257143022410 5ustar00rootroot00000000000000i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p10000644000000000000000000000002614275257143022651 0ustar00rootroot00000000000000nplurals=1; plural=0; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p2b0000644000000000000000000000003214275257143023011 0ustar00rootroot00000000000000nplurals=2; plural=n > 1; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3a0000644000000000000000000000007014275257143023013 0ustar00rootroot00000000000000nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3b0000644000000000000000000000007614275257143023022 0ustar00rootroot00000000000000nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3c0000644000000000000000000000013214275257143023014 0ustar00rootroot00000000000000nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3d0000644000000000000000000000014514275257143023021 0ustar00rootroot00000000000000nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3e0000644000000000000000000000011314275257143023015 0ustar00rootroot00000000000000nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3f0000644000000000000000000000012514275257143023021 0ustar00rootroot00000000000000nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p3g0000644000000000000000000000005414275257143023023 0ustar00rootroot00000000000000nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p4a0000644000000000000000000000011714275257143023016 0ustar00rootroot00000000000000nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; i18nspector-0.27.1/tests/fuzzing/plural-forms/input/p4b0000644000000000000000000000016014275257143023015 0ustar00rootroot00000000000000nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.27.1/tests/fuzzing/plural-forms/run0000755000000000000000000000250514275257143022005 0ustar00rootroot00000000000000#!/bin/sh # Copyright © 2015-2018 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -e here=$(dirname "$0") input="$here/input" output="$here/output" [ -e "$output/" ] && input=- export AFL_FAST_CAL=1 exec py-afl-fuzz -i "$input" -o "$output" -T i18nspector-plural-forms -- python3 "$here/test.py" i18nspector-0.27.1/tests/fuzzing/plural-forms/test.py0000644000000000000000000000337014275257143022605 0ustar00rootroot00000000000000# Copyright © 2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys import afl sys.path[0] += '/../../..' from lib import gettext def test(s): try: (n, expr) = gettext.parse_plural_forms(s) except gettext.PluralFormsSyntaxError: return del n for i in range(200): try: expr(i) except OverflowError: return except ZeroDivisionError: return def main(): while afl.loop(max=1000): s = sys.stdin.buffer.read() # pylint: disable=no-member s = s.decode('UTF-8', 'replace') test(s) os._exit(0) # pylint: disable=protected-access if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/run-nose0000755000000000000000000000272014275257143016627 0ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright © 2013-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys import tempfile import nose sys.path[0] += '/..' from tests import blackbox_tests if __name__ == '__main__': with tempfile.TemporaryDirectory(prefix='i18nspector.tests.') as tmpdir: os.environ['XDG_CACHE_HOME'] = tmpdir nose.main(addplugins=[blackbox_tests.nose_plugin()]) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_changelog.py0000644000000000000000000000773114275257143020502 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import re import lib.tags from .tools import ( assert_not_equal, collect_yielded, ) here = os.path.dirname(__file__) docdir = os.path.join(here, os.pardir, 'doc') summary_re = re.compile( '^ [*] Summary of tag changes:((?:\n .*)+\n)', re.MULTILINE ) summary_details_re = re.compile( r'\A\n' r'(?:' r' [+] Added:\n' r'(?P(?:' r' - [\w-]+\n' r')+))?' r'(?:' r' [+] Renamed:\n' r'(?P(?:' r' - [\w-]+ [(]from [\w-]+[)]\n' r')+))?' r'\Z' ) rename_re = re.compile( r'([\w-]+) [(]from ([\w-]+)[)]' ) @collect_yielded def test_tags(): path = os.path.join(docdir, 'changelog') with open(path, 'rt', encoding='UTF-8') as file: changelog = file.read() summaries = summary_re.findall(changelog) changelog_tags = set() def add(info, tag): del info if tag in changelog_tags: raise AssertionError('changelog adds tag twice: ' + tag) changelog_tags.add(tag) def remove(info, tag): del info if tag not in changelog_tags: raise AssertionError('changelog removes non-existent tag: ' + tag) changelog_tags.remove(tag) def rename(info, removed_tag, added_tag): assert_not_equal(removed_tag, added_tag) remove(info, removed_tag) add(info, added_tag) def check(info, tag): del info if tag not in changelog_tags: raise AssertionError('tag not in changelog: ' + tag) if tag not in data_tags: raise AssertionError('changelog adds unknown tag: ' + tag) for summary in reversed(summaries): match = summary_details_re.match(summary) for key, lines in match.groupdict().items(): if lines is None: continue lines = [l[8:] for l in lines.splitlines()] if key == 'added': for tag in lines: yield add, 'add', tag elif key == 'renamed': for line in lines: added_tag, removed_tag = rename_re.match(line).groups() yield rename, 'rename', removed_tag, added_tag else: assert False data_tags = frozenset(tag.name for tag in lib.tags.iter_tags()) for tag in sorted(changelog_tags | data_tags): yield check, 'check', tag def test_trailing_whitespace(): path = os.path.join(docdir, 'changelog') unreleased = False with open(path, 'rt', encoding='UTF-8') as file: for n, line in enumerate(file, 1): if n == 1 and ' UNRELEASED;' in line: unreleased = True if n == 3 and unreleased and line == ' * \n': continue line = line.rstrip('\n') if line[-1:].isspace(): raise AssertionError(f'trailing whitespace at line {n}') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_domains.py0000644000000000000000000000640714275257143020204 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import lib.domains as M from .tools import ( assert_false, assert_is, assert_raises, assert_true, ) class test_special_domains: def t(self, domain, special=True): result = M.is_special_domain(domain) if special: assert_true(result) else: assert_false(result) def test_ok(self): self.t('test.jwilk.net', False) def test_in_addr_apra(self): self.t('119.216.184.93.in-addr.arpa') def test_ip6_arpa(self): self.t('7.a.a.0.7.9.0.1.7.4.4.1.f.b.6.2.d.6.0.0.0.2.2.0.0.0.8.2.6.0.6.2.ip6.arpa') def test_test(self): self.t('test') self.t('eggs.test') def test_localhost(self): self.t('localhost') self.t('eggs.localhost') def test_invalid(self): self.t('invalid') self.t('eggs.invalid') def test_example(self): self.t('example') for tld in 'com', 'net', 'org': self.t(f'example.{tld}') self.t(f'eggs.example.{tld}') class test_special_domain_emails: def t(self, email, special=True): result = M.is_email_in_special_domain(email) if special: assert_true(result) else: assert_false(result) def test_valid(self): self.t('jwilk@test.jwilk.net', False) def test_special(self): self.t('jwilk@example.net') def test_no_at(self): with assert_raises(ValueError): self.t('jwilk%jwilk.net') class test_dotless_domains: def t(self, domain, dotless=True): result = M.is_dotless_domain(domain) assert_is(result, dotless) def test_dotless(self): self.t('net') def test_dotfull(self): self.t('jwilk.net', False) self.t('example.jwilk.net', False) class test_dotless_emails: def t(self, email, dotless=True): result = M.is_email_in_dotless_domain(email) assert_is(result, dotless) def test_dotless(self): self.t('jwilk@net') def test_dotfull(self): self.t('jwilk@example.net', False) def test_no_at(self): with assert_raises(ValueError): self.t('jwilk%jwilk.net') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_encodings.py0000644000000000000000000002064414275257143020522 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import curses.ascii import sys import unittest import lib.encodings as E from . import tools from .tools import ( assert_equal, assert_false, assert_is_none, assert_not_in, assert_raises, assert_true, collect_yielded, ) class test_is_portable_encoding: def test_found(self): assert_true(E.is_portable_encoding('ISO-8859-2')) def test_found_(self): assert_true(E.is_portable_encoding('ISO_8859-2')) def test_found_nonpython(self): assert_false(E.is_portable_encoding('KOI8-T')) assert_true(E.is_portable_encoding('KOI8-T', python=False)) def test_notfound(self): assert_false(E.is_portable_encoding('ISO-8859-16')) assert_false(E.is_portable_encoding('ISO-8859-16', python=False)) class test_propose_portable_encoding: def test_identity(self): encoding = 'ISO-8859-2' portable_encoding = E.propose_portable_encoding(encoding) assert_equal(portable_encoding, encoding) @collect_yielded def test_found(self): def t(encoding, expected_portable_encoding): portable_encoding = E.propose_portable_encoding(encoding) assert_equal(portable_encoding, expected_portable_encoding) yield t, 'ISO8859-2', 'ISO-8859-2' yield t, 'ISO_8859-2', 'ISO-8859-2' yield t, 'Windows-1250', 'CP1250' def test_notfound(self): portable_encoding = E.propose_portable_encoding('ISO-8859-16') assert_is_none(portable_encoding) class test_ascii_compatibility: @collect_yielded def test_portable(self): def t(encoding): assert_true(E.is_ascii_compatible_encoding(encoding)) assert_true(E.is_ascii_compatible_encoding(encoding, missing_ok=False)) for encoding in E.get_portable_encodings(): yield t, encoding @collect_yielded def test_incompatible(self): def t(encoding): assert_false(E.is_ascii_compatible_encoding(encoding)) assert_false(E.is_ascii_compatible_encoding(encoding, missing_ok=False)) yield t, 'UTF-7' yield t, 'UTF-16' def _test_missing(self, encoding): assert_false(E.is_ascii_compatible_encoding(encoding)) with assert_raises(E.EncodingLookupError): E.is_ascii_compatible_encoding(encoding, missing_ok=False) @collect_yielded def test_non_text(self): t = self._test_missing yield t, 'base64_codec' yield t, 'bz2_codec' yield t, 'hex_codec' yield t, 'quopri_codec' yield t, 'rot_13' yield t, 'uu_codec' yield t, 'zlib_codec' def test_missing(self): self._test_missing('eggs') class test_get_character_name: def test_latin(self): for i in range(ord('a'), ord('z')): u = chr(i) name = E.get_character_name(u) assert_equal(name, 'LATIN SMALL LETTER ' + u.upper()) u = chr(i).upper() name = E.get_character_name(u) assert_equal(name, 'LATIN CAPITAL LETTER ' + u) def test_c0(self): for i, curses_name in zip(range(0, 0x20), curses.ascii.controlnames): u = chr(i) name = E.get_character_name(u) expected_name = 'control character ' + curses_name assert_equal(name, expected_name) def test_del(self): name = E.get_character_name('\x7F') assert_equal(name, 'control character DEL') def test_c1(self): for i in range(0x80, 0xA0): u = chr(i) name = E.get_character_name(u) assert_true(name.startswith('control character ')) def test_uniqueness(self): names = set() for i in range(0, 0x100): u = chr(i) name = E.get_character_name(u) assert_not_in(name, names) names.add(name) def test_non_character(self): name = E.get_character_name('\uFFFE') assert_equal(name, 'non-character') name = E.get_character_name('\uFFFF') assert_equal(name, 'non-character') def test_lookup_error(self): with assert_raises(ValueError): E.get_character_name('\uE000') class test_extra_encoding: @tools.fork_isolation def test_install(self): encoding = 'VISCII' def enc(): ''.encode(encoding) def dec(): b'.'.decode(encoding) try: enc() except LookupError: pass else: raise unittest.SkipTest( 'python{ver[0]}.{ver[1]} supports the {enc} encoding'.format( ver=sys.version_info, enc=encoding ) ) with assert_raises(LookupError): dec() E.install_extra_encodings() enc() dec() @tools.fork_isolation def test_8859(self): E.install_extra_encodings() encoding = '8859-2' portable_encoding = E.propose_portable_encoding(encoding) assert_equal('ISO-' + encoding, portable_encoding) @tools.fork_isolation def test_not_allowed(self): encoding = 'TSCII' def enc(): ''.encode(encoding) try: enc() except LookupError: pass else: raise unittest.SkipTest( 'python{ver[0]}.{ver[1]} supports the {enc} encoding'.format( ver=sys.version_info, enc=encoding ) ) E.install_extra_encodings() with assert_raises(LookupError): enc() _viscii_unicode = 'Ti\u1EBFng Vi\u1EC7t' _viscii_bytes = b'Ti\xAAng Vi\xAEt' @tools.fork_isolation def test_8b_encode(self): E.install_extra_encodings() u = self._viscii_unicode b = u.encode('VISCII') assert_equal(b, self._viscii_bytes) @tools.fork_isolation def test_8b_encode_error(self): E.install_extra_encodings() u = self._viscii_unicode with assert_raises(UnicodeEncodeError): u.encode('KOI8-RU') @tools.fork_isolation def test_8b_decode(self): E.install_extra_encodings() b = self._viscii_bytes u = b.decode('VISCII') assert_equal(u, self._viscii_unicode) @tools.fork_isolation def test_8b_decode_error(self): E.install_extra_encodings() b = self._viscii_bytes with assert_raises(UnicodeDecodeError): b.decode('KOI8-T') _euc_tw_unicode = '\u4E2D\u6587' _euc_tw_bytes = b'\xC4\xE3\xC5\xC6' @tools.fork_isolation def test_mb_encode(self): E.install_extra_encodings() u = self._euc_tw_unicode b = u.encode('EUC-TW') assert_equal(b, self._euc_tw_bytes) @tools.fork_isolation def test_mb_encode_error(self): E.install_extra_encodings() u = self._viscii_unicode with assert_raises(UnicodeEncodeError): u.encode('EUC-TW') @tools.fork_isolation def test_mb_decode(self): E.install_extra_encodings() b = self._euc_tw_bytes u = b.decode('EUC-TW') assert_equal(u, self._euc_tw_unicode) @tools.fork_isolation def test_mb_decode_error(self): E.install_extra_encodings() b = self._viscii_bytes with assert_raises(UnicodeDecodeError): b.decode('EUC-TW') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_gettext.py0000644000000000000000000005402214275257143020232 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import datetime import lib.gettext as M from .tools import ( assert_equal, assert_false, assert_is_instance, assert_is_none, assert_is_not_none, assert_less, assert_raises, assert_true, ) class test_header_fields: def test_nonempty(self): # XXX Update this number after editing data/header-fields: expected = 12 assert_equal(len(M.header_fields), expected) def test_no_x(self): for field in M.header_fields: assert_false(field.startswith('X-')) def test_valid(self): for field in M.header_fields: assert_true(M.is_valid_field_name(field)) class test_header_parser: def t(self, message, expected): parsed = list(M.parse_header(message)) assert_equal(parsed, expected) def test_ok(self): self.t( 'Menu: spam\nVikings: yes\n', [{'Menu': 'spam'}, {'Vikings': 'yes'}], ) def test_no_trailing_nl(self): self.t( 'Menu: spam\nVikings: yes', [{'Menu': 'spam'}, {'Vikings': 'yes'}], ) def test_invalid_field_name(self): self.t( 'Menu :spam\nVikings: yes\n', ['Menu :spam', {'Vikings': 'yes'}], ) def test_no_field(self): self.t( 'Spam\nVikings: yes\n', ['Spam', {'Vikings': 'yes'}], ) def test_continuation(self): self.t( 'Menu: spam,\n eggs\nVikings: yes\n', [{'Menu': 'spam,'}, ' eggs', {'Vikings': 'yes'}], ) class test_plural_exp: error = M.PluralFormsSyntaxError def t(self, s, n=None, fn=None): f = M.parse_plural_expression(s) if n is not None: assert_is_not_none(fn) assert_equal(f(n), fn) def test_const(self): n = 42 self.t(str(n), 0, n) def test_const_overflow(self): m = (1 << 32) - 1 self.t(str(m), m, m) with assert_raises(OverflowError): self.t(str(m + 1), m + 1, False) self.t(str(m + 1), m + 42, False) def test_var(self): n = 42 self.t('n', n, n) def test_var_overflow(self): m = (1 << 32) - 1 self.t('n', m, m) with assert_raises(OverflowError): self.t('n', m + 1, False) self.t('42', m + 1, 42) def test_add(self): self.t('17 + n', 6, 23) def test_add_overflow(self): m = (1 << 32) - 1 self.t('n + 42', m - 42, m) with assert_raises(OverflowError): self.t('n + 42', m - 41, False) self.t('n + 42', m - 23, False) def test_sub(self): self.t('n - 23', 37, 14) def test_sub_overflow(self): with assert_raises(OverflowError): self.t('n - 23', 6, False) def test_mul(self): self.t('6 * n', 7, 42) def test_mul_overflow(self): m = (1 << 32) - 1 assert m % 17 == 0 self.t('n * 17', m / 17, m) with assert_raises(OverflowError): self.t('n * 17', (m / 17) + 1, False) self.t('n * 2', (m + 1) / 2, False) def test_div(self): self.t('105 / n', 17, 6) def test_div_by_0(self): with assert_raises(ZeroDivisionError): self.t('105 / n', 0, False) def test_mod(self): self.t('105 % n', 17, 3) def test_mod_by_0(self): with assert_raises(ZeroDivisionError): self.t('105 % n', 0, False) def test_and(self): self.t('n && 6', 7, 1) self.t('n && 6', 0, 0) self.t('n && (6 / 0)', 0, 0) # no ZeroDivisionError self.t('n && 0', 7, 0) self.t('n && 0', 0, 0) def test_or(self): self.t('n || 6', 7, 1) self.t('n || (6 / 0)', 7, 1) # no ZeroDivisionError self.t('n || 6', 0, 1) self.t('n || 0', 7, 1) self.t('n || 0', 0, 0) def test_gt(self): self.t('n > 37', 23, 0) self.t('n > 37', 37, 0) self.t('n > 37', 42, 1) def test_ge(self): self.t('n >= 37', 23, 0) self.t('n >= 37', 37, 1) self.t('n >= 37', 42, 1) def test_lt(self): self.t('n < 37', 23, 1) self.t('n < 37', 37, 0) self.t('n < 37', 42, 0) def test_le(self): self.t('n <= 37', 23, 1) self.t('n <= 37', 37, 1) self.t('n <= 37', 42, 0) def test_eq(self): self.t('n == 37', 23, 0) self.t('n == 37', 37, 1) self.t('n == 37', 42, 0) def test_ne(self): self.t('n != 37', 23, 1) self.t('n != 37', 37, 0) self.t('n != 37', 42, 1) def test_multi_compare(self): self.t('1 < n == 3 <= 4', 1, 0) # False in Python self.t('1 < n == 3 <= 4', 2, 1) # False in Python self.t('1 < n == 3 <= 4', 3, 1) # True in Python self.t('1 < n == 3 <= 4', 4, 1) # False in Python self.t('2 == 2 == n', 2, 0) # True in Python self.t('2 == 2 == n', 1, 1) # False in Python def test_neg(self): self.t('! n', 0, 1) self.t('! n', 1, 0) self.t('! n', 69, 0) def test_neg_precedence(self): self.t('! 6 + 7', 0, 7) self.t('0 + ! 0') def test_conditional(self): s = 'n ? 3 : 7' self.t(s, 0, 7) self.t(s, 1, 3) def test_nested_conditional(self): self.t('(2 ? 3 : 7) ? 23 : 37') def test_badly_nested_conditional(self): with assert_raises(self.error): self.t('2 ? (3 : 7 ? ) : 23') def test_unary_minus(self): with assert_raises(self.error): self.t('-37') with assert_raises(self.error): self.t('23 + (-37)') def test_unary_plus(self): with assert_raises(self.error): self.t('+42') with assert_raises(self.error): self.t('23 + (+37)') def test_func_call(self): with assert_raises(self.error): self.t('n(42)') with assert_raises(self.error): self.t('42(n)') def test_unbalanced_parentheses(self): with assert_raises(self.error): self.t('(6 * 7') with assert_raises(self.error): self.t('6 * 7)') with assert_raises(self.error): self.t('6) * (7') def test_dangling_binop(self): with assert_raises(self.error): self.t('6 +') def test_junk_token(self): with assert_raises(self.error): self.t('6 # 7') def test_shift(self): with assert_raises(self.error): self.t('6 << 7') with assert_raises(self.error): self.t('6 >> 7') def test_pow(self): with assert_raises(self.error): self.t('6 ** 7') def test_floor_div(self): with assert_raises(self.error): self.t('6 // 7') def test_tuple(self): with assert_raises(self.error): self.t('()') with assert_raises(self.error): self.t('(6, 7)') def test_starred(self): with assert_raises(self.error): self.t('*42') def test_exotic_whitespace(self): with assert_raises(self.error): self.t('6 *\xA07') def test_empty(self): with assert_raises(self.error): self.t('') with assert_raises(self.error): self.t(' ') class test_codomain: def t(self, s, min_, max_=None): if max_ is None: max_ = min_ f = M.parse_plural_expression(s) cd = f.codomain() if min_ is None: assert max_ is None assert_is_none(cd) else: assert_equal(cd, (min_, max_)) def test_num(self): self.t('0', 0, 0) self.t('42', 42, 42) m = (1 << 32) - 1 self.t(str(m), m, m) # no overflow self.t(str(m + 1), None) # overflow self.t(str(m + 23), None) # overflow def test_zero_div(self): self.t('n / 0', None) self.t('(n / 0) + 23', None) self.t('23 + (n / 0)', None) self.t('! (n / 0)', None) self.t('0 < n/0', None) self.t('n/0 < 0', None) self.t('0 < n/0 < 0', None) def test_mod(self): self.t('n % 42', 0, 41) def test_mod_mod(self): self.t('(23 + n%15) % 42', 23, 37) def test_mod_0(self): self.t('n % 0', None) def test_add(self): self.t( '(6 + n%37) + (7 + n%23)', (6 + 7), 6 + 7 + 36 + 22 ) def test_add_max_overflow(self): m = (1 << 32) - 1 self.t( '(37 + n%4242424242) + (23 + n%4242424242)', 37 + 23, m ) def test_add_min_overflow(self): self.t( '(4242424242 + n%37) + (4242424242 + n%23)', None ) def test_sub(self): self.t( '(6 + n%37) - (7 + n%23)', 0, 6 + 36 - 7 ) self.t( '(37 + n%6) - (23 + n%7)', 37 - 23 - 6, 37 + 5 - 23 ) def test_sub_overflow(self): self.t( '(23 - n%6) - (23 + n%6)', # no overflow for n=0 0, 0 ) self.t( '(23 + n%6) - (37 + n%7)', # always overflows None ) def test_mul(self): self.t( '(6 + n%37) * (7 + n%23)', 6 * 7, (6 + 37 - 1) * (7 + 23 - 1) ) def test_mul_max_overflow(self): m = (1 << 32) - 1 self.t('(n + 6) * 7', 42, m) def test_mul_min_overflow(self): m = (1 << 32) - 1 assert m % 17 == 0 self.t( str(m // 17) + ' * (n + 17)', m, m ) self.t( str(m // 17) + ' * (n + 18)', None ) self.t( str((m + 1) // 2) + ' * (n + 2)', None ) def test_div(self): self.t( '(42 + n%63) / (6 + n%7)', 42 // (6 + 7), (42 + 63 - 1) // 6, ) def test_not(self): self.t('! (n % 7)', 0, 1) self.t('! (6 + n % 7)', 0, 0) self.t('! 0', 1, 1) def r(self, x, y, *, var='n'): if x == y: s = str(x) else: w = y - x + 1 assert w >= 2 s = f'{x} + ({var})%{w}' self.t(s, x, y) return s def t_cmp(self, ccmp, pycmp): sl = '1 + n%3' for x in range(4): for y in range(x, 5): sr = self.r(x, y, var='n/3') s = f'{sl} {ccmp} {sr}' vals = { int(pycmp(i, j)) for i in range(1, 4) for j in range(x, y + 1) } self.t(s, min(vals), max(vals)) n = 42 s = f'{n} {ccmp} {n}' self.t(s, pycmp(n, n), pycmp(n, n)) def test_lt(self): self.t_cmp('<', int.__lt__) def test_le(self): self.t_cmp('<=', int.__le__) def test_gt(self): self.t_cmp('>', int.__gt__) def test_ge(self): self.t_cmp('>=', int.__ge__) def test_eq(self): self.t_cmp('==', int.__eq__) def test_ne(self): self.t_cmp('!=', int.__ne__) def t_bool(self, cop, pyop): ranges = [ (x, y) for x in range(0, 3) for y in range(x, 3) ] for lx, ly in ranges: sl = self.r(lx, ly, var='n%3') for rx, ry in ranges: sr = self.r(rx, ry, var='n/3') s = f'{sl} {cop} {sr}' vals = { int(pyop(i, j)) for i in range(lx, ly + 1) for j in range(rx, ry + 1) } self.t(s, min(vals), max(vals)) def test_and(self): def op_and(x, y): return bool(x and y) self.t_bool('&&', op_and) def test_and_error(self): self.t('n && (n / 0) && 0', 0, 0) # doesn't raise exception for n==0 self.t('1 && (n / 0) && 0', None) # always raises exception def test_or(self): def op_or(x, y): return bool(x or y) self.t_bool('||', op_or) def test_or_error(self): self.t('n || (n / 0) || 1', 1, 1) # doesn't raise exception for n>0 self.t('0 || (n / 0) || 1', None) # always raises exception def test_cond_error(self): self.t('(n / 0) ? 37 : 42', None) def test_cond_always_true(self): self.t('1 ? 37 : n', 37, 37) def test_cond_always_false(self): self.t('0 ? n : 37', 37, 37) def test_cond_true_branch_error(self): self.t('n ? (n / 0) : 37', 37, 37) def test_cond_false_branch_error(self): self.t('n ? 37 : (n / 0)', 37, 37) def test_cond_both_branches_error(self): self.t('n ? (n / 0) : (n / 0)', None) def test_cond_both_branches_ok(self): self.t('n ? 37 : 42', 37, 42) self.t( 'n ? (6 + n%23) : (7 + n%37)', 6, 37 + 7 - 1 ) class test_period: def t(self, s, offset, period=None): f = M.parse_plural_expression(s) op = f.period() if offset is None: assert period is None assert_is_none(op) else: assert_equal(op, (offset, period)) def test_num(self): self.t('42', 0, 1) def test_const_mod(self): self.t('n % 42', 0, 42) self.t('n % 0', None) def test_binop(self): self.t('n + (n % 37)', None) self.t('(n % 37) + n', None) self.t('(n % 6) + (n % 14)', 0, 42) self.t('(n % 641) * (n % 6700417)', None) # overflow def test_unaryop(self): self.t('!n', None) self.t('!(n % 37)', 0, 37) def _cmp_shift(self, op): def e(n, op, m): return eval(str(n) + op + str(m)) # pylint: disable=eval-used return e(0, op, 0) != e(1, op, 0) def test_const_cmp(self): for op in {'!=', '==', '<', '<=', '>', '>='}: shift = self._cmp_shift(op) self.t(f'n {op} {37}', 37 + shift, 1) def test_const_cmp_overflow(self): ops = {'!=', '==', '<', '<=', '>', '>='} m = (1 << 32) - 1 for op in ops: shift = self._cmp_shift(op) self.t(f'n {op} {(m - 1)}', m - 1 + shift, 1) if shift: self.t(f'n {op} {m}', None) else: self.t(f'n {op} {m}', m, 1) self.t(f'n {op} {(m + 1)}', None) self.t(f'n {op} {(m + 42)}', None) def test_compare(self): self.t('n < (n % 37)', None) self.t('(n % 37) < n', None) self.t('(n % 6) < (n % 14)', 0, 42) self.t('(n % 641) < (n % 6700417)', None) # overflow def test_boolop(self): self.t('n && (n % 37)', None) self.t('(n % 37) && n', None) self.t('(n % 6) && (n % 14)', 0, 42) self.t('(n % 641) && (n % 6700417)', None) # overflow def test_ifexp(self): self.t('n ? (n % 3) : (n % 7)', None) self.t('(n % 2) ? n : (n % 7)', None) self.t('(n % 2) ? (n % 3) : n', None) self.t('(n % 2) ? (n % 3) : (n % 7)', 0, 42) self.t('(n % 2) ? (n % 3) : (n % 715827883)', None) # overflow def test_num_overflow(self): m = (1 << 32) - 1 self.t(str(m), 0, 1) self.t(str(m + 1), None) self.t(str(m + 42), None) def test_real_world(self): self.t('0', 0, 1) self.t('n != 1', 2, 1) self.t('n > 1', 2, 1) self.t('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3', 0, 100) self.t('n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2', 1, 100) self.t('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2', 0, 100) self.t('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2', 0, 100) self.t('n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2', 2, 100) self.t('n==1 ? 0 : (n>=2 && n<=4) ? 1 : 2', 5, 1) self.t('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2', 2, 100) self.t('n==1 ? 0 : n==2 ? 1 : 2', 3, 1) self.t('n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2', 2, 100) class test_plural_forms: error = M.PluralFormsSyntaxError def t(self, s, *, n, ljunk='', rjunk=''): if ljunk or rjunk: with assert_raises(self.error): M.parse_plural_forms(s) else: (n0, expr0) = M.parse_plural_forms(s) del expr0 assert_equal(n0, n) (n1, expr1, ljunk1, rjunk1) = M.parse_plural_forms(s, strict=False) # pylint: disable=unbalanced-tuple-unpacking del expr1 assert_equal(n1, n) assert_equal(ljunk1, ljunk) assert_equal(rjunk1, rjunk) def test_nplurals_0(self): with assert_raises(self.error): self.t('nplurals=0; plural=0;', n=0) def test_nplurals_positive(self): for n in 1, 2, 10, 42: self.t(f'nplurals={n}; plural=0;', n=n) def test_missing_trailing_semicolon(self): self.t('nplurals=1; plural=0', n=1) def test_junk(self): self.t('eggsnplurals=1; plural=0;', n=1, ljunk='eggs') self.t('nplurals=1; plural=0;ham', n=1, rjunk='ham') self.t('baconnplurals=1; plural=0;spam', n=1, ljunk='bacon', rjunk='spam') class test_fix_date_format: def t(self, old, expected): if expected is None: with assert_raises(M.DateSyntaxError): M.fix_date_format(old) else: new = M.fix_date_format(old) assert_is_not_none(new) assert_equal(new, expected) def tbp(self, old): with assert_raises(M.BoilerplateDate): M.fix_date_format(old) def test_boilerplate(self): self.tbp('YEAR-MO-DA HO:MI+ZONE') self.tbp('YEAR-MO-DA HO:MI +ZONE') def test_partial_boilerplate(self): self.tbp('2000-05-15 22:MI+0200') self.tbp('2002-10-15 HO:MI+ZONE') self.tbp('2003-07-DA 11:31+0100') self.tbp('2004-MO-DA HO:MI+ZONE') self.tbp('2006-10-24 18:00+ZONE') self.tbp('2010-11-01 HO:MI+0000') def test_okay(self): d = '2010-10-13 01:27+0200' self.t(d, d) def test_double_space(self): d = '2011-11-08 16:49+0200' self.t(d, d.replace(' ', ' ')) def test_space_before_tz(self): self.t( '2010-05-12 18:36 -0400', '2010-05-12 18:36-0400', ) def test_seconds(self): self.t( '2010-03-27 12:44:19+0100', '2010-03-27 12:44+0100', ) def test_colon_in_tz(self): self.t( '2001-06-25 18:55+02:00', '2001-06-25 18:55+0200', ) def test_t_separator(self): self.t( '2003-04-01T09:08+0500', '2003-04-01 09:08+0500', ) def test_missing_tz(self): self.t('2002-01-01 03:05', None) def test_tz_hint(self): assert_equal( M.fix_date_format('2002-01-01 03:05', tz_hint='+0900'), '2002-01-01 03:05+0900', ) def test_gmt_before_tz(self): self.t( '2001-07-28 11:19GMT+0200', '2001-07-28 11:19+0200', ) self.t( '2001-12-20 17:22UTC+0100', '2001-12-20 17:22+0100', ) def test_abbrev(self): # OK: self.t( '2004-04-20 13:24+CEST', '2004-04-20 13:24+0200', ) self.t( '2010-02-17 13:11 PST', '2010-02-17 13:11-0800', ) self.t( '2001-01-06 12:12GMT', '2001-01-06 12:12+0000', ) def test_abbrev_ambiguous(self): self.t('2004-04-14 21:35+CDT', None) self.t('2000-06-14 23:23+EST', None) # XXX In tzdata 2014f, EST stands only for (US) Eastern Time Zone, i.e. # -0500. But in the previous version of tzdata it could also stand for # (Australian) Eastern Standard/Summer Time. # https://mm.icann.org/pipermail/tz/2014-June/021089.html def test_abbrev_nonexistent(self): self.t('2005-12-20 10:33+JEST', None) def test_only_date(self): self.t('2008-01-09', None) def test_nonexistent(self): self.t('2010-02-29 19:49+0200', None) class test_parse_date: t = staticmethod(M.parse_date) def test_nonexistent(self): with assert_raises(M.DateSyntaxError): self.t('2010-02-29 19:49+0200') def test_existent(self): d = self.t('2003-09-08 21:26+0200') assert_equal(d.second, 0) assert_is_instance(d, datetime.datetime) assert_equal(str(d), '2003-09-08 21:26:00+02:00') def test_epoch(self): d = self.t('2008-04-03 16:06+0300') assert_less(M.epoch, d) class test_string_formats: def test_nonempty(self): # XXX Update this number after editing data/string-formats: expected = 28 assert_equal(len(M.string_formats), expected) def test_lowercase(self): for s in M.string_formats: assert_is_instance(s, str) assert_true(s) assert_equal(s, s.lower()) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_iconv.py0000644000000000000000000000363314275257143017666 0ustar00rootroot00000000000000# Copyright © 2013-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import lib.iconv as M from .tools import ( assert_equal, assert_raises, ) class _test: u = None b = None e = None def test_encode(self): b = M.encode(self.u, self.e) assert_equal(b, self.b) def test_decode(self): u = M.decode(self.b, self.e) assert_equal(u, self.u) class test_iso2(_test): u = 'Żrą łódź? Część miń!' b = b'\xAFr\xB1 \xB3\xF3d\xBC? Cz\xEA\xB6\xE6 mi\xF1!' e = 'ISO-8859-2' class test_tcvn(_test): u = 'Do bạch kim rất quý, sẽ để lắp vô xương' b = b'Do b\xB9ch kim r\xCAt qu\xFD, s\xCF \xAE\xD3 l\xBEp v\xAB x\xAD\xACng' e = 'TCVN-5712' def test_incomplete_char(): b = 'Ę'.encode('UTF-8')[:1] with assert_raises(UnicodeDecodeError): M.decode(b, 'UTF-8') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_ling.py0000644000000000000000000004574514275257143017513 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import unittest import lib.encodings import lib.ling from . import tools from .tools import ( assert_equal, assert_false, assert_in, assert_is, assert_is_instance, assert_is_none, assert_not_equal, assert_not_in, assert_raises, assert_true, collect_yielded, ) L = lib.ling T = lib.ling.Language E = lib.encodings class test_fix_codes: def t(self, l1, l2): lang = L.parse_language(l1) assert_equal(str(lang), l1) if l1 == l2: assert_is_none(lang.fix_codes()) else: assert_is(lang.fix_codes(), True) assert_equal(str(lang), l2) def test_2_to_2(self): self.t('grc', 'grc') self.t('grc_GR', 'grc_GR') def test_1_to_1(self): self.t('el', 'el') self.t('el_GR', 'el_GR') def test_2t_to_1(self): self.t('ell', 'el') self.t('ell_GR', 'el_GR') def test_2b_to_1(self): self.t('gre', 'el') self.t('gre_GR', 'el_GR') def test_ll_not_found(self): with assert_raises(L.FixingLanguageCodesFailed): self.t('ry', '') def test_cc_not_found(self): with assert_raises(L.FixingLanguageCodesFailed): self.t('el_RY', '') def test_language_repr(): # Language.__repr__() is never used by i18nspector itself, # but it's useful for debugging test failures. lng = T('el') assert_equal(repr(lng), '') class test_language_equality: # ==, !=, is_almost_equal() def test_eq(self): l1 = T('el', 'GR') l2 = T('el', 'GR') assert_equal(l1, l2) assert_equal(l2, l1) def test_ne(self): l1 = T('el') l2 = T('el', 'GR') assert_not_equal(l1, l2) assert_not_equal(l2, l1) def test_ne_other_type(self): l1 = T('el') assert_not_equal(l1, 42) assert_not_equal(42, l1) def test_almost_equal(self): l1 = T('el') l2 = T('el', 'GR') assert_true(l1.is_almost_equal(l2)) assert_true(l2.is_almost_equal(l1)) def test_not_almost_equal(self): l1 = T('el', 'GR') l2 = T('grc', 'GR') assert_false(l1.is_almost_equal(l2)) assert_false(l2.is_almost_equal(l1)) def test_not_almost_equal_other_type(self): l1 = T('el') with assert_raises(TypeError): l1.is_almost_equal(42) class test_remove_encoding: def t(self, l1, l2): lang = L.parse_language(l1) assert_equal(str(lang), l1) if l1 == l2: assert_is_none(lang.remove_encoding()) else: assert_is(lang.remove_encoding(), True) assert_equal(str(lang), l2) def test_without_encoding(self): self.t('el', 'el') def test_with_encoding(self): self.t('el.UTF-8', 'el') class test_remove_nonlinguistic_modifier: def t(self, l1, l2): lang = L.parse_language(l1) assert_equal(str(lang), l1) if l1 == l2: assert_is_none(lang.remove_nonlinguistic_modifier()) else: assert_is(lang.remove_nonlinguistic_modifier(), True) assert_equal(str(lang), l2) def test_quot(self): self.t('en@quot', 'en@quot') self.t('en@boldquot', 'en@boldquot') def test_latin(self): self.t('sr@latin', 'sr@latin') def test_euro(self): self.t('de_AT@euro', 'de_AT') class test_lookup_territory_code: def test_found(self): cc = L.lookup_territory_code('GR') assert_equal(cc, 'GR') def test_not_found(self): cc = L.lookup_territory_code('RG') assert_is_none(cc) class test_get_language_for_name: def t(self, name, expected): lang = L.get_language_for_name(name) assert_is_instance(lang, T) assert_equal(str(lang), expected) def test_found(self): self.t('Greek', 'el') def test_found_multi(self): self.t('Old Church Slavonic', 'cu') def test_found_as_ascii(self): self.t('Norwegian Bokmål', 'nb') def test_found_semicolon(self): self.t('Chichewa; Nyanja', 'ny') def test_found_comma(self): self.t('Ndebele, South', 'nr') def test_found_comma_as_semicolon(self): self.t('Pashto, Pushto', 'ps') def test_lone_comma(self): with assert_raises(LookupError): self.t(',', None) def test_not_found(self): with assert_raises(LookupError): self.t('Nadsat', None) class test_parse_language: def test_ll(self): lang = L.parse_language('el') assert_equal(lang.language_code, 'el') assert_is_none(lang.territory_code) assert_is_none(lang.encoding) assert_is_none(lang.modifier) def test_lll(self): lang = L.parse_language('ell') assert_equal(lang.language_code, 'ell') assert_is_none(lang.territory_code) assert_is_none(lang.encoding) assert_is_none(lang.modifier) def test_ll_cc(self): lang = L.parse_language('el_GR') assert_equal(lang.language_code, 'el') assert_equal(lang.territory_code, 'GR') assert_is_none(lang.encoding) assert_is_none(lang.modifier) def test_ll_cc_enc(self): lang = L.parse_language('el_GR.UTF-8') assert_equal(lang.language_code, 'el') assert_equal(lang.territory_code, 'GR') assert_equal(lang.encoding, 'UTF-8') assert_is_none(lang.modifier) def test_ll_cc_modifier(self): lang = L.parse_language('en_US@quot') assert_equal(lang.language_code, 'en') assert_equal(lang.territory_code, 'US') assert_is_none(lang.encoding) assert_equal(lang.modifier, 'quot') def test_syntax_error(self): with assert_raises(L.LanguageSyntaxError): L.parse_language('GR') class test_get_primary_languages: def test_found(self): langs = L.get_primary_languages() assert_in('el', langs) def test_not_found(self): langs = L.get_primary_languages() assert_not_in('ry', langs) @collect_yielded def test_iso_639(self): def t(lang_str): lang = L.parse_language(lang_str) assert_is_none(lang.fix_codes()) assert_equal(str(lang), lang_str) for lang_str in L.get_primary_languages(): yield t, lang_str class test_get_plural_forms: def t(self, lang): lang = L.parse_language(lang) return lang.get_plural_forms() def test_found_ll(self): assert_equal( self.t('el'), ['nplurals=2; plural=n != 1;'] ) def test_found_ll_cc(self): assert_equal( self.t('el_GR'), ['nplurals=2; plural=n != 1;'] ) def test_en_ca(self): assert_equal( self.t('en'), self.t('en_CA'), ) def test_pt_br(self): assert_not_equal( self.t('pt'), self.t('pt_BR'), ) def test_not_known(self): assert_is_none(self.t('la')) def test_not_found(self): assert_is_none(self.t('ry')) class test_principal_territory: def test_found_2(self): # el -> el_GR lang = L.parse_language('el') cc = lang.get_principal_territory_code() assert_equal(cc, 'GR') def test_remove_2(self): # el_GR -> el lang = L.parse_language('el_GR') assert_equal(str(lang), 'el_GR') rc = lang.remove_principal_territory_code() assert_is(rc, True) assert_equal(str(lang), 'el') def test_found_3(self): # ang -> ang_GB lang = L.parse_language('ang') cc = lang.get_principal_territory_code() assert_equal(cc, 'GB') def test_remove_3(self): # ang_GB -> ang lang = L.parse_language('ang_GB') assert_equal(str(lang), 'ang_GB') rc = lang.remove_principal_territory_code() assert_is(rc, True) assert_equal(str(lang), 'ang') def test_no_principal_territory_code(self): # en -/-> en_US lang = L.parse_language('en') cc = lang.get_principal_territory_code() assert_is_none(cc) def test_no_remove_principal_territory_code(self): # en_US -/-> en lang = L.parse_language('en_US') assert_equal(str(lang), 'en_US') rc = lang.remove_principal_territory_code() assert_is_none(rc) assert_equal(str(lang), 'en_US') def test_not_found(self): lang = L.parse_language('ry') cc = lang.get_principal_territory_code() assert_is_none(cc) class test_unrepresentable_characters: def test_ll_bad(self): lang = L.parse_language('pl') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_ok(self): lang = L.parse_language('pl') result = lang.get_unrepresentable_characters('ISO-8859-2') assert_equal(result, []) def test_ll_cc_bad(self): lang = L.parse_language('pl_PL') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_cc_ok(self): lang = L.parse_language('pl_PL') result = lang.get_unrepresentable_characters('ISO-8859-2') assert_equal(result, []) def test_ll_mod_bad(self): lang = L.parse_language('en@quot') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_mod_ok(self): lang = L.parse_language('en@quot') result = lang.get_unrepresentable_characters('UTF-8') assert_equal(result, []) def test_ll_cc_mod_bad(self): lang = L.parse_language('en_US@quot') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_cc_mod_ok(self): lang = L.parse_language('en_US@quot') result = lang.get_unrepresentable_characters('UTF-8') assert_equal(result, []) def test_ll_optional(self): # U+0178 (LATIN CAPITAL LETTER Y WITH DIAERESIS) is not representable # in ISO-8859-1, but we normally turn a blind eye to this. lang = L.parse_language('fr') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_equal(result, []) result = lang.get_unrepresentable_characters('ISO-8859-1', strict=True) assert_not_equal(result, []) def test_ll_not_found(self): lang = L.parse_language('ry') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_is_none(result) @tools.fork_isolation def test_extra_encoding(self): encoding = 'GEORGIAN-PS' lang = L.parse_language('pl') with assert_raises(LookupError): ''.encode(encoding) E.install_extra_encodings() result = lang.get_unrepresentable_characters(encoding) assert_not_equal(result, []) @collect_yielded def test_glibc_supported(): def t(l): lang = L.parse_language(l) try: lang.fix_codes() except L.FixingLanguageCodesFailed: # FIXME: some ISO-639-3 codes are not recognized yet if len(l.split('_')[0]) == 3: raise unittest.SkipTest('expected failure') reason = locales_to_skip.get(l) if reason is not None: raise unittest.SkipTest(reason) raise assert_equal(str(lang), l) try: file = open('/usr/share/i18n/SUPPORTED', encoding='ASCII') # pylint: disable=consider-using-with except OSError as exc: raise unittest.SkipTest(exc) locales = set() with file: for line in file: if line[:1] in {'#', '\n'}: continue locale, *rest = line.split() del rest if (locale + '.').startswith('iw_IL.'): # iw_IL is obsolete continue if locale.startswith('C.'): continue locales.add(locale) misnamed_locales = { # glibc 2.21 had two misnamed locales: 'bh_IN.UTF-8', # should be bhb_IN 'tu_IN.UTF-8', # should be tcy_IN } locales_to_skip = {} if locales & misnamed_locales == misnamed_locales: for l in misnamed_locales: locales_to_skip[l] = 'https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=032c510db06c' for l in sorted(locales): yield t, l @collect_yielded def test_poedit(): # https://github.com/vslavik/poedit/blob/v1.8.1-oss/src/language_impl_legacy.h # There won't be any new names in this table, # so it's safe to hardcode them all here. def t(name, poedit_ll): poedit_ll = L.parse_language(poedit_ll) ll = L.get_language_for_name(name) assert_equal(ll, poedit_ll) def x(name, poedit_ll): poedit_ll = L.parse_language(poedit_ll) with assert_raises(LookupError): L.get_language_for_name(name) raise unittest.SkipTest('expected failure') yield t, 'Abkhazian', 'ab' yield t, 'Afar', 'aa' yield t, 'Afrikaans', 'af' yield t, 'Albanian', 'sq' yield t, 'Amharic', 'am' yield t, 'Arabic', 'ar' yield t, 'Armenian', 'hy' yield t, 'Assamese', 'as' yield t, 'Avestan', 'ae' yield t, 'Aymara', 'ay' yield t, 'Azerbaijani', 'az' yield t, 'Bashkir', 'ba' yield t, 'Basque', 'eu' yield t, 'Belarusian', 'be' yield t, 'Bengali', 'bn' yield t, 'Bislama', 'bi' yield t, 'Bosnian', 'bs' yield t, 'Breton', 'br' yield t, 'Bulgarian', 'bg' yield t, 'Burmese', 'my' yield t, 'Catalan', 'ca' yield t, 'Chamorro', 'ch' yield t, 'Chechen', 'ce' yield t, 'Chichewa; Nyanja', 'ny' yield t, 'Chinese', 'zh' yield t, 'Church Slavic', 'cu' yield t, 'Chuvash', 'cv' yield t, 'Cornish', 'kw' yield t, 'Corsican', 'co' yield t, 'Croatian', 'hr' yield t, 'Czech', 'cs' yield t, 'Danish', 'da' yield t, 'Dutch', 'nl' yield t, 'Dzongkha', 'dz' yield t, 'English', 'en' yield t, 'Esperanto', 'eo' yield t, 'Estonian', 'et' yield t, 'Faroese', 'fo' yield t, 'Fijian', 'fj' yield t, 'Finnish', 'fi' yield t, 'French', 'fr' yield t, 'Frisian', 'fy' yield t, 'Friulian', 'fur' yield t, 'Gaelic', 'gd' yield t, 'Galician', 'gl' yield t, 'Georgian', 'ka' yield t, 'German', 'de' yield t, 'Greek', 'el' yield t, 'Guarani', 'gn' yield t, 'Gujarati', 'gu' yield t, 'Hausa', 'ha' yield t, 'Hebrew', 'he' yield t, 'Herero', 'hz' yield t, 'Hindi', 'hi' yield t, 'Hiri Motu', 'ho' yield t, 'Hungarian', 'hu' yield t, 'Icelandic', 'is' yield t, 'Indonesian', 'id' yield t, 'Interlingua', 'ia' yield t, 'Interlingue', 'ie' yield t, 'Inuktitut', 'iu' yield t, 'Inupiaq', 'ik' yield t, 'Irish', 'ga' yield t, 'Italian', 'it' yield t, 'Japanese', 'ja' yield t, 'Javanese', 'jv' # https://github.com/vslavik/poedit/pull/193 yield t, 'Kalaallisut', 'kl' yield t, 'Kannada', 'kn' yield t, 'Kashmiri', 'ks' yield t, 'Kazakh', 'kk' yield t, 'Khmer', 'km' yield t, 'Kikuyu', 'ki' yield t, 'Kinyarwanda', 'rw' yield t, 'Komi', 'kv' yield t, 'Korean', 'ko' yield t, 'Kuanyama', 'kj' yield t, 'Kurdish', 'ku' yield t, 'Kyrgyz', 'ky' yield t, 'Lao', 'lo' yield t, 'Latin', 'la' yield t, 'Latvian', 'lv' yield t, 'Letzeburgesch', 'lb' yield t, 'Lingala', 'ln' yield t, 'Lithuanian', 'lt' yield t, 'Macedonian', 'mk' yield t, 'Malagasy', 'mg' yield t, 'Malay', 'ms' yield t, 'Malayalam', 'ml' yield t, 'Maltese', 'mt' yield t, 'Maori', 'mi' yield t, 'Marathi', 'mr' yield t, 'Marshall', 'mh' yield t, 'Moldavian', 'ro_MD' # XXX poedit uses deprecated "mo" yield t, 'Mongolian', 'mn' yield t, 'Nauru', 'na' yield t, 'Navajo', 'nv' yield t, 'Ndebele, South', 'nr' yield t, 'Ndonga', 'ng' yield t, 'Nepali', 'ne' yield t, 'Northern Sami', 'se' yield t, 'Norwegian Bokmal', 'nb' yield t, 'Norwegian Nynorsk', 'nn' yield t, 'Occitan', 'oc' yield t, 'Oriya', 'or' yield t, 'Ossetian; Ossetic', 'os' yield t, 'Pali', 'pi' yield t, 'Panjabi', 'pa' yield t, 'Pashto, Pushto', 'ps' yield t, 'Persian', 'fa' yield t, 'Polish', 'pl' yield t, 'Portuguese', 'pt' yield t, 'Quechua', 'qu' yield t, 'Rhaeto-Romance', 'rm' yield t, 'Romanian', 'ro' yield t, 'Rundi', 'rn' yield t, 'Russian', 'ru' yield t, 'Samoan', 'sm' yield t, 'Sangro', 'sg' yield t, 'Sanskrit', 'sa' yield t, 'Sardinian', 'sc' yield t, 'Serbian', 'sr' yield t, 'Sesotho', 'st' yield t, 'Setswana', 'tn' yield t, 'Shona', 'sn' yield t, 'Sindhi', 'sd' yield t, 'Sinhalese', 'si' yield t, 'Siswati', 'ss' yield t, 'Slovak', 'sk' yield t, 'Slovenian', 'sl' yield t, 'Somali', 'so' yield t, 'Spanish', 'es' yield t, 'Sundanese', 'su' yield t, 'Swahili', 'sw' yield t, 'Swedish', 'sv' yield t, 'Tagalog', 'tl' yield t, 'Tahitian', 'ty' yield t, 'Tajik', 'tg' yield t, 'Tamil', 'ta' yield t, 'Tatar', 'tt' yield t, 'Telugu', 'te' yield t, 'Thai', 'th' yield t, 'Tibetan', 'bo' yield t, 'Tigrinya', 'ti' yield t, 'Tonga', 'to' yield t, 'Tsonga', 'ts' yield t, 'Turkish', 'tr' yield t, 'Turkmen', 'tk' yield t, 'Twi', 'tw' yield t, 'Ukrainian', 'uk' yield t, 'Urdu', 'ur' yield t, 'Uyghur', 'ug' yield t, 'Uzbek', 'uz' yield t, 'Vietnamese', 'vi' yield t, 'Volapuk', 'vo' yield t, 'Walloon', 'wa' yield t, 'Welsh', 'cy' yield t, 'Wolof', 'wo' yield t, 'Xhosa', 'xh' yield t, 'Yiddish', 'yi' yield t, 'Yoruba', 'yo' yield t, 'Zhuang', 'za' yield t, 'Zulu', 'zu' # TODO: yield x, '(Afan) Oromo', 'om' yield x, 'Bihari', 'bh' # "bh" is marked as collective in ISO-639-2 yield x, 'Serbian (Latin)', 'sr_RS@latin' yield x, 'Serbo-Croatian', 'sh' # "sh" is deprecated in favor of "sr", "hr", "bs" # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_misc.py0000644000000000000000000001013014275257143017471 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import datetime import os import stat import tempfile import time import lib.misc as M from .tools import ( assert_almost_equal, assert_equal, assert_is_instance, assert_is_not_none, assert_raises, assert_true, ) from . import tools class test_unsorted: def t(self, lst, expected): assert_is_instance(lst, list) r = M.unsorted(lst) assert_equal(r, expected) r = M.unsorted(x for x in lst) assert_equal(r, expected) def test_0(self): self.t([], None) def test_1(self): self.t([17], None) def test_2(self): self.t([17, 23], None) self.t([23, 17], (23, 17)) def test_3(self): self.t([17, 23, 37], None) self.t([17, 37, 23], (37, 23)) self.t([23, 17, 37], (23, 17)) self.t([23, 37, 17], (37, 17)) self.t([37, 17, 23], (37, 17)) self.t([37, 23, 17], (37, 23)) def test_inf(self): def iterable(): yield 17 yield 37 while True: yield 23 r = M.unsorted(iterable()) assert_equal(r, (37, 23)) class test_check_sorted: def test_sorted(self): M.check_sorted([17, 23, 37]) def test_unsorted(self): with assert_raises(M.DataIntegrityError) as cm: M.check_sorted([23, 37, 17]) assert_equal(str(cm.exception), '37 > 17') def test_sorted_vk(): lst = ['eggs', 'spam', 'ham'] d = dict(enumerate(lst)) assert_equal( lst, list(M.sorted_vk(d)) ) class test_utc_now: def test_types(self): now = M.utc_now() assert_is_instance(now, datetime.datetime) assert_is_not_none(now.tzinfo) assert_equal(now.tzinfo.utcoffset(now), datetime.timedelta(0)) @tools.fork_isolation def test_tz_resistance(self): def t(tz): os.environ['TZ'] = tz time.tzset() return M.utc_now() now1 = t('Etc/GMT-4') now2 = t('Etc/GMT+2') tdelta = (now1 - now2).total_seconds() assert_almost_equal(tdelta, 0, delta=0.75) class test_format_range: def t(self, x, y, max, expected): # pylint: disable=redefined-builtin assert_equal( M.format_range(range(x, y), max=max), expected ) def test_max_is_lt_4(self): with assert_raises(ValueError): self.t(5, 10, 3, None) def test_len_lt_max(self): self.t(5, 10, 4, '5, 6, ..., 9') self.t(23, 43, 6, '23, 24, 25, 26, ..., 42') def test_len_eq_max(self): self.t(5, 10, 5, '5, 6, 7, 8, 9') def test_len_gt_max(self): self.t(5, 10, 6, '5, 6, 7, 8, 9') def test_huge(self): self.t(5, 42 ** 17, 5, '5, 6, 7, ..., 3937657486715347520027492351') def test_throwaway_tempdir(): with M.throwaway_tempdir('test'): d = tempfile.gettempdir() st = os.stat(d) assert_equal(stat.S_IMODE(st.st_mode), 0o700) assert_true(stat.S_ISDIR(st.st_mode)) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_moparser.py0000644000000000000000000000475414275257143020405 0ustar00rootroot00000000000000# Copyright © 2014-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import random import lib.moparser as M from .tools import ( assert_equal, assert_raises, ) from . import tools def parser_for_bytes(data): with tools.temporary_file(suffix='.mo') as file: file.write(data) file.flush() return M.Parser(file.name) class test_magic: def test_value(self): assert_equal(M.little_endian_magic, b'\xDE\x12\x04\x95') assert_equal(M.big_endian_magic, b'\x95\x04\x12\xDE') def test_short(self): for j in range(0, 3): data = M.little_endian_magic[:j] with assert_raises(M.SyntaxError) as cm: parser_for_bytes(data) assert_equal(str(cm.exception), 'unexpected magic') def test_full(self): for magic in {M.little_endian_magic, M.big_endian_magic}: with assert_raises(M.SyntaxError) as cm: parser_for_bytes(magic) assert_equal(str(cm.exception), 'truncated file') def test_random(self): while True: random_magic = bytes( random.randrange(0, 0x100) for i in range(0, 4) ) if random_magic in {M.little_endian_magic, M.big_endian_magic}: continue break with assert_raises(M.SyntaxError) as cm: parser_for_bytes(random_magic) assert_equal(str(cm.exception), 'unexpected magic') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_polib4us.py0000644000000000000000000000377014275257143020313 0ustar00rootroot00000000000000# Copyright © 2013-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import polib import lib.polib4us as M from .tools import ( assert_list_equal, assert_true, ) from . import tools minimal_header = r''' msgid "" msgstr "Content-Type: text/plain; charset=US-ASCII\n" ''' class test_codecs: @tools.fork_isolation def test_trailing_obsolete_message(self): s = minimal_header + ''' msgid "a" msgstr "b" #~ msgid "b" #~ msgstr "c" ''' def t(): with tools.temporary_file(mode='wt', encoding='ASCII') as file: file.write(s) file.flush() po = polib.pofile(file.name) assert_true(po[-1].obsolete) t() M.install_patches() t() @tools.fork_isolation def test_flag_splitting(): M.install_patches() e = polib.POEntry() e.flags = ['fuzzy,c-format'] assert_list_equal( e.flags, ['fuzzy', 'c-format'] ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_strformat_c.py0000644000000000000000000004066414275257143021100 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import struct import sys import unittest.mock import lib.strformat.c as M from .tools import ( assert_equal, assert_greater, assert_is_instance, assert_raises, assert_sequence_equal, collect_yielded, ) def test_INT_MAX(): struct.pack('=i', M.INT_MAX) with assert_raises(struct.error): struct.pack('=i', M.INT_MAX + 1) def is_glibc(): try: os.confstr('CS_GNU_LIBC_VERSION') except (ValueError, OSError): return False return True def test_NL_ARGMAX(): plat = sys.platform if plat.startswith('linux') and is_glibc(): assert_equal( M.NL_ARGMAX, os.sysconf('SC_NL_ARGMAX') ) else: raise unittest.SkipTest('Test specific to Linux with glibc') small_NL_ARGMAX = unittest.mock.patch('lib.strformat.c.NL_ARGMAX', 42) # Setting NL_ARGMAX to a small number makes the *_index_out_of_range() tests # much faster. def test_lone_percent(): with assert_raises(M.Error): M.FormatString('%') def test_invalid_conversion_spec(): with assert_raises(M.Error): M.FormatString('%!') def test_add_argument(): fmt = M.FormatString('%s') with assert_raises(RuntimeError): fmt.add_argument(2, None) def test_text(): fmt = M.FormatString('eggs%dbacon%dspam') assert_equal(len(fmt), 5) fmt = list(fmt) assert_equal(fmt[0], 'eggs') assert_equal(fmt[2], 'bacon') assert_equal(fmt[4], 'spam') class test_types: def t(self, s, tp, warn_type=None, integer=False): fmt = M.FormatString(s) [conv] = fmt assert_is_instance(conv, M.Conversion) assert_equal(conv.type, tp) if tp == 'void': assert_sequence_equal(fmt.arguments, []) else: [[arg]] = fmt.arguments assert_equal(arg.type, tp) if warn_type is None: assert_sequence_equal(fmt.warnings, []) else: [warning] = fmt.warnings assert_is_instance(warning, warn_type) assert_equal(conv.integer, integer) @collect_yielded def test_integer(self): def t(s, tp, warn_type=None): if s[-1] == 'n': tp += ' *' integer = False else: integer = True return (self.t, s, tp, warn_type, integer) for c in 'din': yield t('%hh' + c, 'signed char') yield t('%h' + c, 'short int') yield t('%' + c, 'int') yield t('%l' + c, 'long int') yield t('%ll' + c, 'long long int') yield t('%L' + c, 'long long int', M.NonPortableConversion) yield t('%q' + c, 'long long int', M.NonPortableConversion) yield t('%j' + c, 'intmax_t') yield t('%z' + c, 'ssize_t') yield t('%Z' + c, 'ssize_t', M.NonPortableConversion) yield t('%t' + c, 'ptrdiff_t') for c in 'ouxX': yield t('%hh' + c, 'unsigned char') yield t('%h' + c, 'unsigned short int') yield t('%' + c, 'unsigned int') yield t('%l' + c, 'unsigned long int') yield t('%ll' + c, 'unsigned long long int') yield t('%L' + c, 'unsigned long long int', M.NonPortableConversion) yield t('%q' + c, 'unsigned long long int', M.NonPortableConversion) yield t('%j' + c, 'uintmax_t') yield t('%z' + c, 'size_t') yield t('%Z' + c, 'size_t', M.NonPortableConversion) yield t('%t' + c, '[unsigned ptrdiff_t]') @collect_yielded def test_double(self): t = self.t for c in 'aefgAEFG': yield t, ('%' + c), 'double' yield t, ('%l' + c), 'double', M.NonPortableConversion yield t, ('%L' + c), 'long double' @collect_yielded def test_char(self): t = self.t yield t, '%c', 'char' yield t, '%lc', 'wint_t' yield t, '%C', 'wint_t', M.NonPortableConversion yield t, '%s', 'const char *' yield t, '%ls', 'const wchar_t *' yield t, '%S', 'const wchar_t *', M.NonPortableConversion @collect_yielded def test_void(self): t = self.t yield t, '%p', 'void *' yield t, '%m', 'void' yield t, '%%', 'void' @collect_yielded def test_c99_macros(self): # pylint: disable=undefined-loop-variable def _t(s, tp): return self.t(s, tp, integer=True) def t(s, tp): return ( _t, f'%<{s.format(c=c, n=n)}>', ('u' if unsigned else '') + tp.format(n=n) ) # pylint: enable=undefined-loop-variable for c in 'diouxX': unsigned = c not in 'di' for n in {8, 16, 32, 64}: yield t('PRI{c}{n}', 'int{n}_t') yield t('PRI{c}LEAST{n}', 'int_least{n}_t') yield t('PRI{c}FAST{n}', 'int_fast{n}_t') yield t('PRI{c}MAX', 'intmax_t') yield t('PRI{c}PTR', 'intptr_t') class test_invalid_length: def t(self, s): with assert_raises(M.LengthError): M.FormatString(s) _lengths = ['hh', 'h', 'l', 'll', 'q', 'j', 'z', 't', 'L'] @collect_yielded def test_double(self): t = self.t for c in 'aefgAEFG': for l in self._lengths: if l in 'lL': continue yield t, ('%' + l + c) @collect_yielded def test_char(self): t = self.t for c in 'cs': for l in self._lengths: if l != 'l': yield t, '%' + l + c yield t, ('%' + l + c.upper()) @collect_yielded def test_void(self): t = self.t for c in 'pm%': for l in self._lengths: yield t, ('%' + l + c) class test_numeration: def test_percent(self): with assert_raises(M.ForbiddenArgumentIndex): M.FormatString('%1$%') def test_errno(self): # FIXME? fmt = M.FormatString('%1$m') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 0) def test_swapped(self): fmt = M.FormatString('%2$s%1$d') assert_equal(len(fmt), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'const char *') def test_numbering_mixture(self): def t(s): with assert_raises(M.ArgumentNumberingMixture): M.FormatString(s) t('%s%2$s') t('%2$s%s') @small_NL_ARGMAX def test_index_out_of_range(self): with assert_raises(M.ArgumentRangeError): M.FormatString('%0$d') def fs(n): s = str.join('', ( f'%{i}$d' for i in range(1, n + 1) )) return M.FormatString(s) fmt = fs(M.NL_ARGMAX) assert_equal(len(fmt), M.NL_ARGMAX) assert_equal(len(fmt.arguments), M.NL_ARGMAX) with assert_raises(M.ArgumentRangeError): fs(M.NL_ARGMAX + 1) def test_initial_gap(self): with assert_raises(M.MissingArgument): M.FormatString('%2$d') def test_gap(self): with assert_raises(M.MissingArgument): M.FormatString('%3$d%1$d') class test_redundant_flag: def t(self, s): fmt = M.FormatString(s) [exc] = fmt.warnings assert_is_instance(exc, M.RedundantFlag) def test_duplicate(self): self.t('%--17d') def test_minus_zero(self): self.t('%-017d') def test_plus_space(self): self.t('%+ d') # TODO: Check for other redundant flags, for example “%+s”. class test_expected_flag: def t(self, s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) @collect_yielded def test_hash(self): for c in 'oxXaAeEfFgG': yield self.t, ('%#' + c) @collect_yielded def test_zero(self): for c in 'diouxXaAeEfFgG': yield self.t, ('%0' + c) @collect_yielded def test_apos(self): for c in 'diufFgG': yield self.t, ("%'" + c) @collect_yielded def test_other(self): for flag in '- +I': for c in 'diouxXaAeEfFgGcCsSpm': yield self.t, ('%' + flag + c) class test_unexpected_flag: def t(self, s): with assert_raises(M.FlagError): M.FormatString(s) @collect_yielded def test_hash(self): for c in 'dicCsSnpm%': yield self.t, ('%#' + c) @collect_yielded def test_zero(self): for c in 'cCsSnpm%': yield self.t, ('%0' + c) @collect_yielded def test_apos(self): for c in 'oxXaAeEcCsSnpm%': yield self.t, ("%'" + c) @collect_yielded def test_other(self): for c in '%n': for flag in '- +I': yield self.t, ('%' + flag + c) class test_width: @collect_yielded def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) for c in 'diouxXaAeEfFgGcCsSp': yield t, ('%1' + c) yield t, '%1m' # FIXME? def test_invalid(self): for c in '%n': with assert_raises(M.WidthError): M.FormatString('%1' + c) def test_too_large(self): fmt = M.FormatString(f'%{M.INT_MAX}d') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 1) with assert_raises(M.WidthRangeError): M.FormatString(f'%{M.INT_MAX + 1}d') def test_variable(self): fmt = M.FormatString('%*s') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'const char *') def _test_index(self, i): fmt = M.FormatString(f'%2$*{i}$s') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'const char *') def test_index(self): self._test_index(1) def test_leading_zero_index(self): self._test_index('01') self._test_index('001') @small_NL_ARGMAX def test_index_out_of_range(self): with assert_raises(M.ArgumentRangeError): M.FormatString('%1$*0$s') def fs(n): s = str.join('', ( f'%{i}$d' for i in range(2, n) )) + f'%1$*{n}$s' return M.FormatString(s) fmt = fs(M.NL_ARGMAX) assert_equal(len(fmt), M.NL_ARGMAX - 1) assert_equal(len(fmt.arguments), M.NL_ARGMAX) with assert_raises(M.ArgumentRangeError): fs(M.NL_ARGMAX + 1) def test_numbering_mixture(self): def t(s): with assert_raises(M.ArgumentNumberingMixture): M.FormatString(s) t('%1$*s') t('%*1$s') t('%s%1$*2$s') t('%1$*2$s%s') class test_precision: @collect_yielded def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) for c in 'diouxXaAeEfFgGsS': yield t, ('%.1' + c) @collect_yielded def test_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) [warning] = fmt.warnings assert_is_instance(warning, M.RedundantFlag) for c in 'diouxX': yield t, ('%0.1' + c) @collect_yielded def test_non_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.warnings, []) for c in 'aAeEfFgG': yield t, ('%0.1' + c) @collect_yielded def test_unexpected(self): def t(s): with assert_raises(M.PrecisionError): M.FormatString(s) for c in 'cCpnm%': yield t, ('%.1' + c) def test_too_large(self): fmt = M.FormatString(f'%.{M.INT_MAX}f') assert_equal(len(fmt), 1) with assert_raises(M.PrecisionRangeError): M.FormatString(f'%.{M.INT_MAX + 1}f') def test_variable(self): fmt = M.FormatString('%.*f') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'double') def _test_index(self, i): fmt = M.FormatString(f'%2$.*{i}$f') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'double') def test_index(self): self._test_index(1) def test_leading_zero_index(self): self._test_index('01') self._test_index('001') @small_NL_ARGMAX def test_index_out_of_range(self): with assert_raises(M.ArgumentRangeError): M.FormatString('%1$.*0$f') def fs(n): s = str.join('', ( f'%{i}$d' for i in range(2, n) )) + f'%1$.*{n}$f' return M.FormatString(s) fmt = fs(M.NL_ARGMAX) assert_equal(len(fmt), M.NL_ARGMAX - 1) assert_equal(len(fmt.arguments), M.NL_ARGMAX) with assert_raises(M.ArgumentRangeError): fs(M.NL_ARGMAX + 1) def test_numbering_mixture(self): def t(s): with assert_raises(M.ArgumentNumberingMixture): M.FormatString(s) t('%1$.*f') t('%.*1$f') t('%f%2$.*1$f') t('%2$.*1$f%f') class test_type_compatibility: def test_okay(self): def t(s, tp): fmt = M.FormatString(s) [args] = fmt.arguments assert_greater(len(args), 1) for arg in args: assert_equal(arg.type, tp) t('%1$d%1$d', 'int') t('%1$d%1$i', 'int') def test_mismatch(self): def t(s): with assert_raises(M.ArgumentTypeMismatch): M.FormatString(s) t('%1$d%1$hd') t('%1$d%1$u') t('%1$d%1$s') @small_NL_ARGMAX def test_too_many_conversions(): def t(s): with assert_raises(M.ArgumentRangeError): M.FormatString(s) s = M.NL_ARGMAX * '%d' fmt = M.FormatString(s) assert_equal(len(fmt), M.NL_ARGMAX) t(s + '%f') t(s + '%*f') t(s + '%.*f') class test_get_last_integer_conversion: def test_overflow(self): fmt = M.FormatString('%s%d') for n in [-1, 0, 3]: with assert_raises(IndexError): fmt.get_last_integer_conversion(n=n) def t(self, s, n, tp=M.Conversion): fmt = M.FormatString(s) conv = fmt.get_last_integer_conversion(n=n) if tp is None: tp = type(tp) assert_is_instance(conv, tp) return conv def test_okay(self): self.t('%d', 1) self.t('%s%d', 1) def test_non_integer(self): self.t('%s', 1, None) self.t('%c', 1, None) def test_too_many(self): self.t('%s%d', 2, None) self.t('%d%d', 2, None) def test_var(self): self.t('%*d', 1) self.t('%*d', 2) self.t('%.*d', 2) self.t('%1$*2$d', 2) self.t('%2$*3$.*1$d', 3) def test_broken_var(self): self.t('%1$*2$d', 1, None) self.t('%1$*2$d%3$d', 2, None) self.t('%1$*3$d%2$d', 2, None) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_strformat_perlbrace.py0000644000000000000000000000352214275257143022605 0ustar00rootroot00000000000000# Copyright © 2016-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import lib.strformat.perlbrace as M from .tools import ( assert_equal, assert_raises, ) def test_lone_lcb(): with assert_raises(M.Error): M.FormatString('{') def test_lone_rcb(): M.FormatString('}') def test_invalid_field(): with assert_raises(M.Error): M.FormatString('{@}') def test_text(): fmt = M.FormatString('bacon') assert_equal(len(fmt), 1) [fld] = fmt assert_equal(fld, 'bacon') class test_named_arguments: def test_good(self): fmt = M.FormatString('{spam}') assert_equal(len(fmt), 1) [fld] = fmt assert_equal(fld, '{spam}') def test_bad(self): with assert_raises(M.Error): M.FormatString('{3ggs}') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_strformat_pybrace.py0000644000000000000000000002136514275257143022300 0ustar00rootroot00000000000000# Copyright © 2016-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import struct import unittest.mock import lib.strformat.pybrace as M from .tools import ( assert_equal, assert_is, assert_is_instance, assert_raises, ) def test_SSIZE_MAX(): struct.pack('=i', M.SSIZE_MAX) with assert_raises(struct.error): struct.pack('=i', M.SSIZE_MAX + 1) small_SSIZE_MAX = unittest.mock.patch('lib.strformat.pybrace.SSIZE_MAX', 42) # Setting SSIZE_ARGMAX to a small number makes it possible to test for # a very large number of arguments without running out of memory. def test_lone_lcb(): with assert_raises(M.Error): M.FormatString('{') def test_lone_rcb(): with assert_raises(M.Error): M.FormatString('}') def test_invalid_field(): with assert_raises(M.Error): M.FormatString('{@}') def test_add_argument(): fmt = M.FormatString('{}') with assert_raises(RuntimeError): fmt.add_argument(None, None) with assert_raises(RuntimeError): fmt.add_argument('eggs', None) def test_text(): fmt = M.FormatString('eggs{}bacon{}spam') assert_equal(len(fmt), 5) fmt = list(fmt) assert_equal(fmt[0], 'eggs') assert_equal(fmt[2], 'bacon') assert_equal(fmt[4], 'spam') class test_types: def t(self, k, *types): types = frozenset(tp.__name__ for tp in types) fmt = M.FormatString('{:' + k + '}') [fld] = fmt assert_is_instance(fld, M.Field) assert_equal(fld.types, types) assert_equal(len(fmt.argument_map), 1) [(key, [afld])] = fmt.argument_map.items() assert_equal(key, 0) assert_is(fld, afld) def test_default(self): self.t('', int, float, str) def test_s(self): self.t('s', str) def test_int(self): for k in 'bcdoxX': self.t(k, int) def test_n(self): self.t('n', int, float) def test_float(self): for k in 'eEfFgG': self.t(k, float) class test_conversion: def t(self, c, k, *types): types = frozenset(tp.__name__ for tp in types) fmt = M.FormatString('{!' + c + ':' + k + '}') [fld] = fmt assert_is_instance(fld, M.Field) assert_equal(fld.types, types) assert_equal(len(fmt.argument_map), 1) [(key, [afld])] = fmt.argument_map.items() assert_equal(key, 0) assert_is(fld, afld) def test_default(self): for c in 'sra': self.t(c, '', int, float, str) def test_s(self): for c in 'sra': self.t(c, 's', str) def test_numeric(self): for c in 'sra': for k in 'bcdoxXneEfFgG': with assert_raises(M.FormatTypeMismatch): self.t(c, k, int) def test_bad(self): with assert_raises(M.ConversionError): self.t('z', '') class test_numbered_arguments: tp_int = frozenset({'int'}) tp_float = frozenset({'float'}) def t(self, s, *types): fmt = M.FormatString(s) assert_equal(len(fmt), len(types)) assert_equal(len(fmt.argument_map), len(types)) for (key, args), (xkey, xtype) in zip(sorted(fmt.argument_map.items()), enumerate(types)): [arg] = args assert_equal(key, xkey) assert_equal(arg.types, frozenset({xtype.__name__})) def test_unnumbered(self): self.t('{:d}{:f}', int, float) def test_numbered(self): self.t('{0:d}{1:f}', int, float) def test_swapped(self): self.t('{1:d}{0:f}', float, int) def test_mixed(self): with assert_raises(M.ArgumentNumberingMixture): self.t('{0:d}{:f}') with assert_raises(M.ArgumentNumberingMixture): self.t('{:d}{0:f}') def test_numbered_out_of_range(self): def t(i): s = ('{' + str(i) + '}') M.FormatString(s) t(M.SSIZE_MAX) with assert_raises(M.ArgumentRangeError): t(M.SSIZE_MAX + 1) @small_SSIZE_MAX def test_unnumbered_out_of_range(self): def t(i): s = '{}' * i M.FormatString(s) t(M.SSIZE_MAX + 1) with assert_raises(M.ArgumentRangeError): t(M.SSIZE_MAX + 2) class test_named_arguments: def test_good(self): fmt = M.FormatString('{spam}') [fld] = fmt [(aname, [afld])] = fmt.argument_map.items() assert_equal(aname, 'spam') assert_is(fld, afld) def test_bad(self): with assert_raises(M.Error): M.FormatString('{3ggs}') class test_format_spec: def test_bad_char(self): with assert_raises(M.Error): M.FormatString('{:@}') def test_bad_letter(self): with assert_raises(M.Error): M.FormatString('{:Z}') def test_comma(self): def t(k): M.FormatString('{:,' + k + '}') t('') for k in 'bcdoxXeEfFgG': t(k) for k in 'ns': with assert_raises(M.Error): t(k) def test_alt_sign(self): def t(c, k): M.FormatString('{:' + c + k + '}') for c in ' +-#': t(c, '') for k in 'bcdoxXneEfFgG': t(c, k) with assert_raises(M.Error): t(c, 's') def test_align(self): def t(c, k): M.FormatString('{:' + c + k + '}') for c in '<>^': t(c, '') for k in 'bcdoxXneEfFgGs': t(c, k) t(c + '0', k) for c in '=0': t(c, '') for k in 'bcdoxXneEfFgG': t(c, k) with assert_raises(M.Error): t(c, 's') def test_width(self): def t(w, k): if k == '\0': k = '' M.FormatString('{:' + str(w) + k + '}') for k in 'bcdoxXneEfFgGs\0': for i in 4, 37, M.SSIZE_MAX: t(i, k) with assert_raises(M.Error): t(M.SSIZE_MAX + 1, k) def test_precision(self): def t(w, k): if k == '\0': k = '' M.FormatString('{:.' + str(w) + k + '}') for k in 'neEfFgGs\0': for i in {4, 37, M.SSIZE_MAX}: t(i, k) with assert_raises(M.Error): t(M.SSIZE_MAX + 1, k) for k in 'bcdoxX': for i in {4, 37, M.SSIZE_MAX, M.SSIZE_MAX + 1}: with assert_raises(M.Error): t(i, k) def test_type_compat(self): def t(k1, k2): s = '{0:' + k1 + '}{0:' + k2 + '}' M.FormatString(s) def e(k1, k2): with assert_raises(M.ArgumentTypeMismatch): t(k1, k2) ks = 'bcdoxXneEfFgGs' compat = [ ('s', 's'), ('bcdoxX', 'bcdoxXn'), ('n', 'bcdoxXneEfFgG'), ('eEfFgG', 'neEfFgG'), ] for k in ks: t(k, '') t('', k) for (k1s, k2s) in compat: for k1 in k1s: for k2 in k2s: t(k1, k2) for k2 in ks: if k2 not in k2s: e(k1, k2) def test_nested_fields(self): def t(v=None, f=None): if v is None: v = '' if f is None: f = '' s = '{' + str(v) + ':{' + str(f) + '}}' return M.FormatString(s) fmt = t() assert_equal(len(fmt.argument_map), 2) t(v=0, f=M.SSIZE_MAX) with assert_raises(M.ArgumentRangeError): t(v=0, f=(M.SSIZE_MAX + 1)) with assert_raises(M.ArgumentNumberingMixture): t(v=0) with assert_raises(M.ArgumentNumberingMixture): t(f=0) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_strformat_python.py0000644000000000000000000002143114275257143022166 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import struct import lib.strformat.python as M from .tools import ( assert_equal, assert_greater, assert_is_instance, assert_raises, assert_sequence_equal, collect_yielded, ) def test_SSIZE_MAX(): struct.pack('=i', M.SSIZE_MAX) with assert_raises(struct.error): struct.pack('=i', M.SSIZE_MAX + 1) def test_lone_percent(): with assert_raises(M.Error): M.FormatString('%') def test_invalid_conversion_spec(): with assert_raises(M.Error): M.FormatString('%!') def test_add_argument(): fmt = M.FormatString('%s') with assert_raises(RuntimeError): fmt.add_argument(None, None) with assert_raises(RuntimeError): fmt.add_argument('eggs', None) def test_text(): fmt = M.FormatString('eggs%dbacon%dspam') assert_equal(len(fmt), 5) fmt = list(fmt) assert_equal(fmt[0], 'eggs') assert_equal(fmt[2], 'bacon') assert_equal(fmt[4], 'spam') class test_map: def t(self, key): s = '%(' + key + ')s' fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.seq_arguments, []) [pkey] = fmt.map_arguments.keys() assert_equal(key, pkey) def test_simple(self): self.t('eggs') def test_balanced_parens(self): self.t('eggs(ham)spam') def test_unbalanced_parens(self): with assert_raises(M.Error): self.t('eggs(ham') class test_types: def t(self, s, tp, warn_type=None): fmt = M.FormatString(s) [conv] = fmt assert_is_instance(conv, M.Conversion) assert_equal(conv.type, tp) assert_equal(len(fmt.map_arguments), 0) if tp == 'None': assert_sequence_equal(fmt.seq_arguments, []) else: [arg] = fmt.seq_arguments assert_equal(arg.type, tp) if warn_type is None: assert_equal(len(fmt.warnings), 0) else: [warning] = fmt.warnings assert_is_instance(warning, warn_type) @collect_yielded def test_integer(self): t = self.t for c in 'oxXdi': yield t, '%' + c, 'int' yield t, '%u', 'int', M.ObsoleteConversion @collect_yielded def test_float(self): t = self.t for c in 'eEfFgG': yield t, '%' + c, 'float' @collect_yielded def test_str(self): t = self.t yield t, '%c', 'chr' yield t, '%s', 'str' @collect_yielded def test_repr(self): t = self.t for c in 'ra': yield t, '%' + c, 'object' @collect_yielded def test_void(self): yield self.t, '%%', 'None' @collect_yielded def test_length(): def t(l): fmt = M.FormatString('%' + l + 'd') [warning] = fmt.warnings assert_is_instance(warning, M.RedundantLength) for l in 'hlL': yield t, l class test_indexing: def test_percent(self): with assert_raises(M.ForbiddenArgumentKey): M.FormatString('%(eggs)%') def test_indexing_mixture(self): def t(s): with assert_raises(M.ArgumentIndexingMixture): M.FormatString(s) t('%s%(eggs)s') t('%(eggs)s%s') # TODO: "u" should be everywhere, where "d" is class test_multiple_flags: def t(self, s): fmt = M.FormatString(s) [exc] = fmt.warnings assert_is_instance(exc, M.RedundantFlag) def test_duplicate(self): self.t('%--17d') def test_minus_zero(self): self.t('%-017d') def test_plus_space(self): self.t('%+ d') @collect_yielded def test_single_flag(): def t(s, expected): fmt = M.FormatString(s) assert_equal(len(fmt), 1) if expected: assert_sequence_equal(fmt.warnings, []) else: [exc] = fmt.warnings assert_is_instance(exc, M.RedundantFlag) for c in 'dioxXeEfFgGcrsa%': yield t, ('%#' + c), (c in 'oxXeEfFgG') for flag in '0 +': yield t, ('%' + flag + c), (c in 'dioxXeEfFgG') yield t, ('%-' + c), True class test_width: @collect_yielded def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.warnings, []) for c in 'dioxXeEfFgGcrsa%': yield t, ('%1' + c) def test_too_large(self): fmt = M.FormatString(f'%{M.SSIZE_MAX}d') assert_equal(len(fmt), 1) assert_equal(len(fmt.seq_arguments), 1) assert_equal(len(fmt.map_arguments), 0) with assert_raises(M.WidthRangeError): M.FormatString(f'%{M.SSIZE_MAX + 1}d') def test_variable(self): fmt = M.FormatString('%*s') assert_equal(len(fmt), 1) assert_equal(len(fmt.map_arguments), 0) [a1, a2] = fmt.seq_arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'str') def test_indexing_mixture(self): def t(s): with assert_raises(M.ArgumentIndexingMixture): M.FormatString(s) t('%*s%(eggs)s') t('%(eggs)s%*s') class test_precision: @collect_yielded def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) for c in 'dioxXeEfFgGrsa': yield t, ('%.1' + c) @collect_yielded def test_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) [warning] = fmt.warnings assert_is_instance(warning, M.RedundantFlag) for c in 'dioxX': yield t, ('%0.1' + c) @collect_yielded def test_non_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.warnings, []) for c in 'eEfFgG': yield t, ('%0.1' + c) @collect_yielded def test_unexpected(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) [warning] = fmt.warnings assert_is_instance(warning, M.RedundantPrecision) for c in 'c%': yield t, ('%.1' + c) def test_too_large(self): fmt = M.FormatString(f'%.{M.SSIZE_MAX}f') assert_equal(len(fmt), 1) with assert_raises(M.PrecisionRangeError): M.FormatString(f'%.{M.SSIZE_MAX + 1}f') def test_variable(self): fmt = M.FormatString('%.*f') assert_equal(len(fmt), 1) assert_equal(len(fmt.map_arguments), 0) [a1, a2] = fmt.seq_arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'float') def test_indexing_mixture(self): def t(s): with assert_raises(M.ArgumentIndexingMixture): M.FormatString(s) t('%.*f%(eggs)f') t('%(eggs)f%.*f') class test_type_compatibility: def test_okay(self): def t(s, tp): fmt = M.FormatString(s) assert_equal(len(fmt.seq_arguments), 0) [args] = fmt.map_arguments.values() assert_greater(len(args), 1) for arg in args: assert_equal(arg.type, tp) t('%(eggs)d%(eggs)d', 'int') t('%(eggs)d%(eggs)i', 'int') def test_mismatch(self): def t(s): with assert_raises(M.ArgumentTypeMismatch): M.FormatString(s) t('%(eggs)d%(eggs)s') def test_seq_conversions(): def t(s, n): fmt = M.FormatString(s) assert_equal(len(fmt.seq_conversions), n) for arg in fmt.seq_conversions: assert_is_instance(arg, M.Conversion) t('%d', 1) t('%d%d', 2) t('eggs%dham', 1) t('%(eggs)d', 0) t('%*d', 1) t('%.*d', 1) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_tags.py0000644000000000000000000001053714275257143017507 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import ast import importlib import inspect import operator import pkgutil import lib.check import lib.tags as M from .tools import ( assert_equal, assert_false, assert_is_instance, assert_raises, assert_true, collect_yielded, ) class test_escape: def t(self, s, expected): result = M.safe_format('{}', s) assert_is_instance(result, M.safestr) assert_equal( result, expected ) def test_safe(self): s = 'fox' self.t(s, s) def test_trailing_newline(self): s = 'fox\n' self.t(s, repr(s)) def test_colon(self): s = 'fox:' self.t(s, repr(s)) def test_space(self): s = 'brown fox' self.t(s, repr(s)) def ast_to_tagnames(node): for child in ast.iter_child_nodes(node): yield from ast_to_tagnames(child) ok = ( isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and node.func.attr == 'tag' and node.args and isinstance(node.args[0], ast.Str) ) if ok: yield node.args[0].s @collect_yielded def test_consistency(): source_tagnames = set() def visit_mod(modname): module = importlib.import_module(modname) source_path = inspect.getsourcefile(module) with open(source_path, 'rt', encoding='UTF-8') as file: source = file.read() node = ast.parse(source, filename=source_path) source_tagnames.update(ast_to_tagnames(node)) visit_mod('lib.check') for _, modname, _ in pkgutil.walk_packages(lib.check.__path__, 'lib.check.'): visit_mod(modname) tagnames = frozenset(tag.name for tag in M.iter_tags()) def test(tag): if tag not in source_tagnames: raise AssertionError('tag never emitted: ' + tag) if tag not in tagnames: raise AssertionError( 'tag missing in data/tags:\n\n' f'[{tag}]\n' 'severity = wishlist\n' 'certainty = wild-guess\n' 'description = TODO' ) for tag in sorted(source_tagnames | tagnames): yield test, tag class test_enums: def t(self, group, *keys): keys = [group[k] for k in keys] operators = ( operator.lt, operator.le, operator.eq, operator.ge, operator.gt, operator.ne, ) for op in operators: for i, x in enumerate(keys): for j, y in enumerate(keys): assert_equal(op(x, y), op(i, j)) if op is operator.eq: assert_false(op(x, j)) elif op is operator.ne: assert_true(op(x, j)) else: with assert_raises(TypeError): op(x, j) def test_severities(self): self.t(M.severities, 'pedantic', 'wishlist', 'minor', 'normal', 'important', 'serious', ) def test_certainties(self): self.t(M.certainties, 'wild-guess', 'possible', 'certain', ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_terminal.py0000644000000000000000000000633114275257143020361 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools import os import pty import sys import lib.terminal as T from .tools import ( assert_equal, ) from . import tools def test_strip_delay(): def t(s, r=b''): assert_equal(T._strip_delay(s), r) # pylint: disable=protected-access t(b'$<1>') t(b'$<2/>') t(b'$<3*>') t(b'$<4*/>') t(b'$<.5*/>') t(b'$<0.6*>') s = b'$<\x9B20>' t(s, s) def _get_colors(): return ( value for name, value in sorted(vars(T.colors).items()) if name.isalpha() ) def assert_tseq_equal(s, expected): class S(str): # assert_equal() does detailed comparison for instances of str, # but not their subclasses. We don't want detailed comparisons, # because diff could contain control characters. pass assert_equal(S(expected), S(s)) def test_dummy(): t = assert_tseq_equal for i in _get_colors(): t(T.attr_fg(i), '') t(T.attr_reset(), '') def pty_fork_isolation(term): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): (master_fd, slave_fd) = pty.openpty() os.dup2(slave_fd, pty.STDOUT_FILENO) os.close(slave_fd) sys.stdout = sys.__stdout__ os.environ['TERM'] = term T.initialize() try: return func(*args, **kwargs) finally: os.close(master_fd) return tools.fork_isolation(wrapper) return decorator @pty_fork_isolation('vt100') def test_vt100(): t = assert_tseq_equal for i in _get_colors(): t(T.attr_fg(i), '') t(T.attr_reset(), '\x1B[m\x0F') @pty_fork_isolation('ansi') def test_ansi(): t = assert_tseq_equal t(T.attr_fg(T.colors.black), '\x1B[30m') t(T.attr_fg(T.colors.red), '\x1B[31m') t(T.attr_fg(T.colors.green), '\x1B[32m') t(T.attr_fg(T.colors.yellow), '\x1B[33m') t(T.attr_fg(T.colors.blue), '\x1B[34m') t(T.attr_fg(T.colors.magenta), '\x1B[35m') t(T.attr_fg(T.colors.cyan), '\x1B[36m') t(T.attr_fg(T.colors.white), '\x1B[37m') t(T.attr_reset(), '\x1B[0;10m') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_version.py0000644000000000000000000000355714275257143020242 0ustar00rootroot00000000000000# Copyright © 2012-2021 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os from lib.cli import __version__ from .tools import ( assert_equal, ) here = os.path.dirname(__file__) docdir = os.path.join(here, os.pardir, 'doc') def test_changelog(): path = os.path.join(docdir, 'changelog') with open(path, 'rt', encoding='UTF-8') as file: line = file.readline() changelog_version = line.split()[1].strip('()') assert_equal(changelog_version, __version__) def test_manpage(): path = os.path.join(docdir, 'manpage.rst') manpage_version = None with open(path, 'rt', encoding='UTF-8') as file: for line in file: if line.startswith(':version:'): manpage_version = line.split()[-1] break assert_equal(manpage_version, __version__) # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/test_xml.py0000644000000000000000000000503614275257143017347 0ustar00rootroot00000000000000# Copyright © 2014-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import re import xml.etree.ElementTree as etree import lib.xml as M from .tools import ( assert_is_none, assert_is_not_none, assert_raises, ) class test_well_formed: def t(self, s): M.check_fragment(s) def test_ok(self): self.t('eggs') self.t('ham spam') def test_unknown_entity(self): self.t('&eggs;') class test_malformed: def t(self, s): with assert_raises(M.SyntaxError): M.check_fragment(s) def test_non_xml_character(self): self.t('\x01') def test_open_tag(self): self.t('ham') def test_closed_tag(self): self.t('eggs') def test_broken_entity(self): self.t('&#eggs;') def test_entity_def(self): s = ( ']>' '&eggs;' ) etree.fromstring(s) self.t(s) class test_name_re(): regexp = re.compile(fr'\A{M.name_re}\Z') def test_good(self): def t(s): match = self.regexp.match(s) assert_is_not_none(match) t(':') t('_') t('e') t('e0') t('eggs') t('eggs-ham') t('eggs:ham') def test_bad(self): def t(s): match = self.regexp.match(s) assert_is_none(match) t('') t('0') t('-') t('e\N{GREEK QUESTION MARK}') # vim:ts=4 sts=4 sw=4 et i18nspector-0.27.1/tests/tools.py0000644000000000000000000001101714275257143016644 0ustar00rootroot00000000000000# Copyright © 2012-2022 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools import os import sys import tempfile import traceback import unittest tc = unittest.TestCase('__hash__') assert_almost_equal = tc.assertAlmostEqual assert_equal = tc.assertEqual assert_false = tc.assertFalse assert_greater = tc.assertGreater assert_in = tc.assertIn assert_is = tc.assertIs assert_is_instance = tc.assertIsInstance assert_is_none = tc.assertIsNone assert_is_not_none = tc.assertIsNotNone assert_less = tc.assertLess assert_list_equal = tc.assertListEqual assert_not_equal = tc.assertNotEqual assert_not_in = tc.assertNotIn assert_raises = tc.assertRaises assert_sequence_equal = tc.assertSequenceEqual assert_true = tc.assertTrue del tc def _collect_yielded(generator): # Convert test generator to something the test harness understands. # For nose, we don't need to do anything. # For pytest, see the tests.conftest module. return generator collect_yielded = _collect_yielded temporary_file = functools.partial( tempfile.NamedTemporaryFile, prefix='i18nspector.tests.', ) temporary_directory = functools.partial( tempfile.TemporaryDirectory, prefix='i18nspector.tests.', ) class IsolatedException(Exception): pass def _n_relevant_tb_levels(tb): n = 0 while tb and '__unittest' not in tb.tb_frame.f_globals: n += 1 tb = tb.tb_next return n def fork_isolation(f): EXIT_EXCEPTION = 101 EXIT_SKIP_TEST = 102 exit = os._exit # pylint: disable=redefined-builtin,protected-access # sys.exit() can't be used here, because the test harness catches # all exceptions, including SystemExit # pylint:disable=consider-using-sys-exit @functools.wraps(f) def wrapper(*args, **kwargs): readfd, writefd = os.pipe() pid = os.fork() if pid == 0: # child: os.close(readfd) try: f(*args, **kwargs) except unittest.SkipTest as exc: s = str(exc).encode('UTF-8') with os.fdopen(writefd, 'wb') as fp: fp.write(s) exit(EXIT_SKIP_TEST) except Exception: # pylint: disable=broad-except exctp, exc, tb = sys.exc_info() s = traceback.format_exception(exctp, exc, tb, _n_relevant_tb_levels(tb)) s = str.join('', s).encode('UTF-8') del tb with os.fdopen(writefd, 'wb') as fp: fp.write(s) exit(EXIT_EXCEPTION) exit(0) else: # parent: os.close(writefd) with os.fdopen(readfd, 'rb') as fp: msg = fp.read() msg = msg.decode('UTF-8').rstrip('\n') pid, status = os.waitpid(pid, 0) if status == (EXIT_EXCEPTION << 8): raise IsolatedException() from Exception('\n\n' + msg) elif status == (EXIT_SKIP_TEST << 8): raise unittest.SkipTest(msg) elif status == 0 and msg == '': pass else: raise RuntimeError(f'unexpected isolated process status {status}') # pylint:enable=consider-using-sys-exit return wrapper basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) basedir = os.environ.get('I18NSPECTOR_BASEDIR', basedir) basedir = os.path.join(basedir, '') os.stat(basedir) datadir = os.path.join(basedir, 'data') os.stat(datadir) sys.path[:0] = [basedir] # vim:ts=4 sts=4 sw=4 et