Skip to content

Commit 3a954f2

Browse files
authored
Merge 75347e3 into 3920fa5
2 parents 3920fa5 + 75347e3 commit 3a954f2

6 files changed

Lines changed: 46 additions & 12 deletions

File tree

sconstruct

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ def makePot(target, source, env):
460460
"--foreign-user",
461461
"--add-comments=Translators:",
462462
"--keyword=pgettext:1c,2",
463+
"--keyword=npgettext:1c,2,3",
463464
"--from-code", "utf-8",
464465
# Needed because xgettext doesn't recognise the .pyw extension.
465466
"--language=python",

source/NVDAObjects/window/winword.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2006-2022 NV Access Limited, Manish Agrawal, Derek Riemer, Babbage B.V.
2+
# Copyright (C) 2006-2023 NV Access Limited, Manish Agrawal, Derek Riemer, Babbage B.V., Cyrille Bougot
33
# This file is covered by the GNU General Public License.
44
# See the file COPYING for more details.
55

@@ -912,8 +912,15 @@ def _normalizeFormatField(self,field,extraDetail=False):
912912
# Translators: line spacing of at least x point
913913
field['line-spacing']=pgettext('line spacing value',"at least %.1f pt")%float(lineSpacingVal)
914914
elif lineSpacingRule==wdLineSpaceMultiple:
915-
# Translators: line spacing of x lines
916-
field['line-spacing']=pgettext('line spacing value',"%.1f lines")%(float(lineSpacingVal)/12.0)
915+
multiLineSpacingVal = float(lineSpacingVal) / 12.0
916+
917+
field['line-spacing'] = npgettext(
918+
'line spacing value',
919+
# Translators: line spacing of x lines
920+
"%.1f line",
921+
"%.1f lines",
922+
multiLineSpacingVal,
923+
) % (multiLineSpacingVal)
917924
revisionType=int(field.pop('wdRevisionType',0))
918925
if revisionType==wdRevisionInsert:
919926
field['revision-insertion']=True

source/appModules/outlook.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
from NVDAObjects.UIA.wordDocument import WordDocument as UIAWordDocument
4646
import languageHandler
4747

48-
4948
PR_LAST_VERB_EXECUTED=0x10810003
5049
VERB_REPLYTOSENDER=102
5150
VERB_REPLYTOALL=103
@@ -352,10 +351,12 @@ def _generateCategoriesText(appointment):
352351
bufLength
353352
) == 0:
354353
raise ctypes.WinError()
354+
categoriesCount = len(categories.split(f"{separatorBuf.value} "))
355355

356356
# Translators: Part of a message reported when on a calendar appointment with one or more categories
357357
# in Microsoft Outlook.
358-
return _("categories {categories}").format(categories=categories)
358+
categoriesText = ngettext("category {categories}", "categories {categories}", categoriesCount)
359+
return categoriesText.format(categories=categories)
359360

360361
def isDuplicateIAccessibleEvent(self,obj):
361362
return False

source/languageHandler.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2007-2021 NV access Limited, Joseph Lee, Łukasz Golonka
2+
# Copyright (C) 2007-2023 NV access Limited, Joseph Lee, Łukasz Golonka, Cyrille Bougot
33
# This file is covered by the GNU General Public License.
44
# See the file COPYING for more details.
55

@@ -288,9 +288,9 @@ def getAvailableLanguages(presentational: bool = False) -> List[Tuple[str, str]]
288288

289289

290290
def makePgettext(translations):
291-
"""Obtaina pgettext function for use with a gettext translations instance.
291+
"""Obtain a pgettext function for use with a gettext translations instance.
292292
pgettext is used to support message contexts,
293-
but Python's gettext module doesn't support this,
293+
but Python 3.7's gettext module doesn't support this,
294294
so NVDA must provide its own implementation.
295295
"""
296296
if isinstance(translations, gettext.GNUTranslations):
@@ -301,14 +301,36 @@ def pgettext(context, message):
301301
except KeyError:
302302
return message
303303
elif isinstance(translations, gettext.NullTranslations):
304-
# A language with out a translation catalog, such as English.
304+
# A language without a translation catalog, such as English.
305305
def pgettext(context, message):
306306
return message
307307
else:
308308
raise ValueError("%s is Not a GNUTranslations or NullTranslations object" % translations)
309309
return pgettext
310310

311311

312+
def makeNpgettext(translations):
313+
"""Obtaina npgettext function for use with a gettext translations instance.
314+
npgettext is used to support message contexts with respect to ngettext,
315+
but Python 3.7's gettext module doesn't support this,
316+
so NVDA must provide its own implementation.
317+
"""
318+
if isinstance(translations, gettext.GNUTranslations):
319+
def npgettext(context, msgSingular, msgPlural, n):
320+
try:
321+
# Look up the message with its context.
322+
return translations._catalog[(f"{context}\x04{msgSingular}", translations.plural(n))]
323+
except KeyError:
324+
return msgSingular if n == 1 else msgPlural
325+
elif isinstance(translations, gettext.NullTranslations):
326+
# A language without a translation catalog, such as English.
327+
def npgettext(context, msgSingular, msgPlural, n):
328+
return msgSingular if n == 1 else msgPlural
329+
else:
330+
raise ValueError("%s is Not a GNUTranslations or NullTranslations object" % translations)
331+
return npgettext
332+
333+
312334
def getLanguageCliArgs() -> Tuple[str, ...]:
313335
"""Returns all command line arguments which were used to set current NVDA language
314336
or an empty tuple if language has not been specified from the CLI."""
@@ -381,10 +403,11 @@ def setLanguage(lang: str) -> None:
381403
if trans is None:
382404
trans = _createGettextTranslation("en")
383405

384-
trans.install()
406+
trans.install(names=['ngettext'])
385407
setLocale(getLanguage())
386-
# Install our pgettext function.
408+
# Install our pgettext and npgettext functions.
387409
builtins.pgettext = makePgettext(trans)
410+
builtins.npgettext = makeNpgettext(trans)
388411

389412
global installedTranslation
390413
installedTranslation = weakref.ref(trans)

source/speech/speech.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,7 @@ def getControlFieldSpeech( # noqa: C901
20412041
# handled further down in the general cases section.
20422042
# This ensures that properties such as name, states and level etc still get reported appropriately.
20432043
# Translators: Number of items in a list (example output: list with 5 items).
2044-
containerContainsText=_("with %s items")%childControlCount
2044+
containerContainsText = ngettext("with %s item", "with %s items", childControlCount) % childControlCount
20452045
elif fieldType=="start_addedToControlFieldStack" and role==controlTypes.Role.TABLE and tableID:
20462046
# Table.
20472047
rowCount=(attrs.get("table-rowcount-presentational") or attrs.get("table-rowcount"))

tests/lint/flake8.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ ignore =
3333

3434
builtins = # inform flake8 about functions we consider built-in.
3535
_, # translation lookup
36+
ngettext, # translation lookup
3637
pgettext, # translation lookup
38+
npgettext, # translation lookup
3739

3840
exclude = # don't bother looking in the following subdirectories / files.
3941
.git,

0 commit comments

Comments
 (0)