arelle-release 2.37.22__py3-none-any.whl → 2.37.25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arelle-release might be problematic. Click here for more details.
- arelle/ModelRelationshipSet.py +3 -0
- arelle/Updater.py +7 -3
- arelle/ValidateDuplicateFacts.py +13 -7
- arelle/XbrlConst.py +22 -0
- arelle/_version.py +2 -2
- arelle/plugin/validate/DBA/rules/fr.py +10 -10
- arelle/plugin/validate/DBA/rules/th.py +1 -1
- arelle/plugin/validate/ESEF/ESEF_Current/ValidateXbrlFinally.py +21 -20
- arelle/plugin/validate/NL/LinkbaseType.py +17 -0
- arelle/plugin/validate/NL/PluginValidationDataExtension.py +155 -4
- arelle/plugin/validate/NL/resources/config.xml +6 -0
- arelle/plugin/validate/NL/rules/fr_kvk.py +1 -1
- arelle/plugin/validate/NL/rules/nl_kvk.py +656 -22
- arelle/utils/validate/DetectScriptsInXhtml.py +1 -4
- arelle/utils/validate/ESEFImage.py +274 -0
- {arelle_release-2.37.22.dist-info → arelle_release-2.37.25.dist-info}/METADATA +1 -1
- {arelle_release-2.37.22.dist-info → arelle_release-2.37.25.dist-info}/RECORD +27 -27
- tests/integration_tests/validation/conformance_suite_configurations/efm_current.py +2 -2
- tests/integration_tests/validation/conformance_suite_configurations/nl_inline_2024.py +52 -28
- tests/integration_tests/validation/conformance_suite_configurations/nl_inline_2024_gaap_other.py +10 -0
- tests/resources/conformance_suites_timing/efm_current.json +8499 -8583
- tests/unit_tests/arelle/plugin/validate/ESEF/ESEF_Current/test_validate_css_url.py +10 -2
- tests/unit_tests/arelle/test_updater.py +43 -14
- arelle/plugin/validate/ESEF/ESEF_Current/Image.py +0 -213
- {arelle_release-2.37.22.dist-info → arelle_release-2.37.25.dist-info}/WHEEL +0 -0
- {arelle_release-2.37.22.dist-info → arelle_release-2.37.25.dist-info}/entry_points.txt +0 -0
- {arelle_release-2.37.22.dist-info → arelle_release-2.37.25.dist-info}/licenses/LICENSE.md +0 -0
- {arelle_release-2.37.22.dist-info → arelle_release-2.37.25.dist-info}/top_level.txt +0 -0
|
@@ -7,7 +7,7 @@ from collections import defaultdict
|
|
|
7
7
|
from dataclasses import dataclass
|
|
8
8
|
from functools import lru_cache
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Any,
|
|
10
|
+
from typing import Any, cast, Iterable
|
|
11
11
|
|
|
12
12
|
import regex as re
|
|
13
13
|
from lxml.etree import _Comment, _ElementTree, _Entity, _ProcessingInstruction, _Element
|
|
@@ -15,8 +15,9 @@ from lxml.etree import _Comment, _ElementTree, _Entity, _ProcessingInstruction,
|
|
|
15
15
|
from arelle import XbrlConst
|
|
16
16
|
from arelle.FunctionIxt import ixtNamespaces
|
|
17
17
|
from arelle.ModelDocument import ModelDocument, Type as ModelDocumentType
|
|
18
|
-
from arelle.ModelDtsObject import ModelConcept
|
|
18
|
+
from arelle.ModelDtsObject import ModelConcept, ModelRelationship
|
|
19
19
|
from arelle.ModelInstanceObject import ModelContext, ModelFact, ModelInlineFootnote, ModelUnit, ModelInlineFact
|
|
20
|
+
from arelle.ModelRelationshipSet import ModelRelationshipSet
|
|
20
21
|
from arelle.ModelObject import ModelObject
|
|
21
22
|
from arelle.ModelValue import QName, qname
|
|
22
23
|
from arelle.ModelXbrl import ModelXbrl
|
|
@@ -68,6 +69,10 @@ EFFECTIVE_KVK_GAAP_OTHER_ENTRYPOINT_FILES = frozenset((
|
|
|
68
69
|
'https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-other-gaap.xsd',
|
|
69
70
|
))
|
|
70
71
|
|
|
72
|
+
NON_DIMENSIONALIZED_LINE_ITEM_LINKROLES = frozenset((
|
|
73
|
+
'https://www.nltaxonomie.nl/kvk/role/lineitems-nondimensional-usage',
|
|
74
|
+
))
|
|
75
|
+
|
|
71
76
|
TAXONOMY_URLS_BY_YEAR = {
|
|
72
77
|
'2024': {
|
|
73
78
|
'https://www.nltaxonomie.nl/kvk/2024-12-31/kvk-annual-report-nlgaap-ext.xsd',
|
|
@@ -103,6 +108,21 @@ QN_DOMAIN_ITEM_TYPES = frozenset((
|
|
|
103
108
|
qname("{http://www.xbrl.org/dtr/type/2022-03-31}nonnum:domainItemType"),
|
|
104
109
|
))
|
|
105
110
|
|
|
111
|
+
SUPPORTED_IMAGE_TYPES_BY_IS_FILE = {
|
|
112
|
+
True: ('gif', 'jpg', 'jpeg', 'png'),
|
|
113
|
+
False: ('gif', 'jpeg', 'png'),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass(frozen=True)
|
|
118
|
+
class AnchorData:
|
|
119
|
+
anchorsInDimensionalElrs: dict[str, frozenset[ModelRelationship]]
|
|
120
|
+
anchorsNotInBase: frozenset[ModelRelationship]
|
|
121
|
+
anchorsWithDimensionItem: frozenset[ModelRelationship]
|
|
122
|
+
anchorsWithDomainItem: frozenset[ModelRelationship]
|
|
123
|
+
extLineItemsNotAnchored: frozenset[ModelConcept]
|
|
124
|
+
extLineItemsWronglyAnchored: frozenset[ModelConcept]
|
|
125
|
+
|
|
106
126
|
|
|
107
127
|
@dataclass(frozen=True)
|
|
108
128
|
class ContextData:
|
|
@@ -112,6 +132,13 @@ class ContextData:
|
|
|
112
132
|
contextsWithSegments: list[ModelContext | None]
|
|
113
133
|
|
|
114
134
|
|
|
135
|
+
@dataclass(frozen=True)
|
|
136
|
+
class DimensionalData:
|
|
137
|
+
domainMembers: frozenset[ModelConcept]
|
|
138
|
+
elrPrimaryItems: dict[str, set[ModelConcept]]
|
|
139
|
+
primaryItems: frozenset[ModelConcept]
|
|
140
|
+
|
|
141
|
+
|
|
115
142
|
@dataclass(frozen=True)
|
|
116
143
|
class ExtensionData:
|
|
117
144
|
extensionConcepts: list[ModelConcept]
|
|
@@ -177,6 +204,8 @@ class LinkbaseData:
|
|
|
177
204
|
basename: str
|
|
178
205
|
element: _Element
|
|
179
206
|
linkbaseType: LinkbaseType | None
|
|
207
|
+
prohibitedBaseConcepts: list[ModelConcept]
|
|
208
|
+
prohibitingLabelElements: list[_Element]
|
|
180
209
|
|
|
181
210
|
@property
|
|
182
211
|
def hasArcs(self) -> bool:
|
|
@@ -249,6 +278,23 @@ class PluginValidationDataExtension(PluginData):
|
|
|
249
278
|
contextsWithSegments=contextsWithSegments,
|
|
250
279
|
)
|
|
251
280
|
|
|
281
|
+
def checkLabels(self, issues: set[ModelConcept| None], modelXbrl: ModelXbrl, parent: ModelConcept, relSet: ModelRelationshipSet, labelrole: str | None, visited: set[ModelConcept]) -> set[ModelConcept| None]:
|
|
282
|
+
visited.add(parent)
|
|
283
|
+
conceptRels = defaultdict(list) # counts for concepts without preferred label role
|
|
284
|
+
for rel in relSet.fromModelObject(parent):
|
|
285
|
+
child = rel.toModelObject
|
|
286
|
+
if child is not None:
|
|
287
|
+
labelrole = rel.preferredLabel
|
|
288
|
+
if not labelrole:
|
|
289
|
+
conceptRels[child].append(rel)
|
|
290
|
+
if child not in visited:
|
|
291
|
+
self.checkLabels(issues, modelXbrl, child, relSet, labelrole, visited)
|
|
292
|
+
for concept, rels in conceptRels.items():
|
|
293
|
+
if len(rels) > 1:
|
|
294
|
+
issues.add(concept)
|
|
295
|
+
visited.remove(parent)
|
|
296
|
+
return issues
|
|
297
|
+
|
|
252
298
|
@lru_cache(1)
|
|
253
299
|
def checkHiddenElements(self, modelXbrl: ModelXbrl) -> HiddenElementsData:
|
|
254
300
|
cssHiddenFacts = set()
|
|
@@ -366,6 +412,70 @@ class PluginValidationDataExtension(PluginData):
|
|
|
366
412
|
factLangs.add(fact.xmlLang)
|
|
367
413
|
return factLangs
|
|
368
414
|
|
|
415
|
+
@lru_cache(1)
|
|
416
|
+
def getAnchorData(self, modelXbrl: ModelXbrl) -> AnchorData:
|
|
417
|
+
extLineItemsNotAnchored = set()
|
|
418
|
+
extLineItemsWronglyAnchored = set()
|
|
419
|
+
widerNarrowerRelSet = modelXbrl.relationshipSet(XbrlConst.widerNarrower)
|
|
420
|
+
generalSpecialRelSet = modelXbrl.relationshipSet(XbrlConst.generalSpecial)
|
|
421
|
+
calcRelSet = modelXbrl.relationshipSet(XbrlConst.summationItems)
|
|
422
|
+
dimensionalData = self.getDimensionalData(modelXbrl)
|
|
423
|
+
primaryItems = dimensionalData.primaryItems
|
|
424
|
+
domainMembers = dimensionalData.domainMembers
|
|
425
|
+
extensionData = self.getExtensionData(modelXbrl)
|
|
426
|
+
for concept in extensionData.extensionConcepts:
|
|
427
|
+
extLineItem = False
|
|
428
|
+
if concept.isPrimaryItem and \
|
|
429
|
+
not concept.isAbstract and \
|
|
430
|
+
concept in primaryItems and \
|
|
431
|
+
not widerNarrowerRelSet.contains(concept) and \
|
|
432
|
+
not calcRelSet.fromModelObject(concept):
|
|
433
|
+
extLineItem = True
|
|
434
|
+
elif concept.isAbstract and \
|
|
435
|
+
concept not in domainMembers and \
|
|
436
|
+
concept.type is not None and \
|
|
437
|
+
not concept.type.isDomainItemType and \
|
|
438
|
+
not concept.isHypercubeItem and \
|
|
439
|
+
not concept.isDimensionItem and \
|
|
440
|
+
not widerNarrowerRelSet.contains(concept):
|
|
441
|
+
extLineItem = True
|
|
442
|
+
if extLineItem:
|
|
443
|
+
if not generalSpecialRelSet.contains(concept):
|
|
444
|
+
extLineItemsNotAnchored.add(concept)
|
|
445
|
+
else:
|
|
446
|
+
extLineItemsWronglyAnchored.add(concept)
|
|
447
|
+
elrsContainingDimensionalRelationships = set(
|
|
448
|
+
ELR
|
|
449
|
+
for arcrole, ELR, linkqname, arcqname in modelXbrl.baseSets.keys()
|
|
450
|
+
if arcrole == "XBRL-dimensions" and ELR is not None)
|
|
451
|
+
anchorsNotInBase = set()
|
|
452
|
+
anchorsWithDomainItem = set()
|
|
453
|
+
anchorsWithDimensionItem = set()
|
|
454
|
+
anchorsInDimensionalElrs = defaultdict(set)
|
|
455
|
+
for anchoringRel in widerNarrowerRelSet.modelRelationships:
|
|
456
|
+
elr = anchoringRel.linkrole
|
|
457
|
+
fromObj = anchoringRel.fromModelObject
|
|
458
|
+
toObj = anchoringRel.toModelObject
|
|
459
|
+
if fromObj is not None and toObj is not None and fromObj.type is not None and toObj.type is not None:
|
|
460
|
+
if not ((not self.isExtensionUri(fromObj.modelDocument.uri, modelXbrl)) ^ (not self.isExtensionUri(toObj.modelDocument.uri, modelXbrl))):
|
|
461
|
+
anchorsNotInBase.add(anchoringRel)
|
|
462
|
+
if fromObj.type.isDomainItemType or toObj.type.isDomainItemType:
|
|
463
|
+
anchorsWithDomainItem.add(anchoringRel)
|
|
464
|
+
elif fromObj.isDimensionItem or toObj.isDimensionItem:
|
|
465
|
+
anchorsWithDimensionItem.add(anchoringRel)
|
|
466
|
+
else:
|
|
467
|
+
if elr in elrsContainingDimensionalRelationships:
|
|
468
|
+
anchorsInDimensionalElrs[elr].add(anchoringRel)
|
|
469
|
+
return AnchorData(
|
|
470
|
+
anchorsInDimensionalElrs={x: frozenset(y) for x, y in anchorsInDimensionalElrs.items()},
|
|
471
|
+
anchorsNotInBase=frozenset(anchorsNotInBase),
|
|
472
|
+
anchorsWithDimensionItem=frozenset(anchorsWithDimensionItem),
|
|
473
|
+
anchorsWithDomainItem=frozenset(anchorsWithDomainItem),
|
|
474
|
+
extLineItemsNotAnchored=frozenset(extLineItemsNotAnchored),
|
|
475
|
+
extLineItemsWronglyAnchored=frozenset(extLineItemsWronglyAnchored),
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
|
|
369
479
|
def getBaseElements(self, modelXbrl: ModelXbrl) -> set[Any | None]:
|
|
370
480
|
return self.checkInlineHTMLElements(modelXbrl).baseElements
|
|
371
481
|
|
|
@@ -399,10 +509,13 @@ class PluginValidationDataExtension(PluginData):
|
|
|
399
509
|
_getDocumentsInDts(modelXbrl.modelDocument)
|
|
400
510
|
return modelDocuments
|
|
401
511
|
|
|
402
|
-
|
|
512
|
+
@lru_cache(1)
|
|
513
|
+
def getDimensionalData(self, modelXbrl: ModelXbrl) -> DimensionalData:
|
|
403
514
|
domainMembers = set() # concepts which are dimension domain members
|
|
515
|
+
elrPrimaryItems = defaultdict(set)
|
|
404
516
|
hcPrimaryItems: set[ModelConcept] = set()
|
|
405
517
|
hcMembers: set[Any] = set()
|
|
518
|
+
primaryItems: set[ModelConcept] = set()
|
|
406
519
|
for hasHypercubeArcrole in (XbrlConst.all, XbrlConst.notAll):
|
|
407
520
|
hasHypercubeRelationships = modelXbrl.relationshipSet(hasHypercubeArcrole).fromModelObjects()
|
|
408
521
|
for hasHcRels in hasHypercubeRelationships.values():
|
|
@@ -413,6 +526,7 @@ class PluginValidationDataExtension(PluginData):
|
|
|
413
526
|
for domMbrRel in modelXbrl.relationshipSet(XbrlConst.domainMember).fromModelObject(sourceConcept):
|
|
414
527
|
if domMbrRel.consecutiveLinkrole == hasHcRel.linkrole: # only those related to this hc
|
|
415
528
|
self.addDomMbrs(modelXbrl, domMbrRel.toModelObject, domMbrRel.consecutiveLinkrole, hcPrimaryItems)
|
|
529
|
+
primaryItems.update(hcPrimaryItems)
|
|
416
530
|
hc = hasHcRel.toModelObject
|
|
417
531
|
for hcDimRel in modelXbrl.relationshipSet(XbrlConst.hypercubeDimension, hasHcRel.consecutiveLinkrole).fromModelObject(hc):
|
|
418
532
|
dim = hcDimRel.toModelObject
|
|
@@ -422,7 +536,18 @@ class PluginValidationDataExtension(PluginData):
|
|
|
422
536
|
if isinstance(dom, ModelConcept):
|
|
423
537
|
self.addDomMbrs(modelXbrl, dom, dimDomRel.consecutiveLinkrole, hcMembers)
|
|
424
538
|
domainMembers.update(hcMembers)
|
|
425
|
-
|
|
539
|
+
if hasHcRel.linkrole in NON_DIMENSIONALIZED_LINE_ITEM_LINKROLES or hcMembers:
|
|
540
|
+
for hcPrimaryItem in hcPrimaryItems:
|
|
541
|
+
if not hcPrimaryItem.isAbstract:
|
|
542
|
+
elrPrimaryItems[hasHcRel.linkrole].add(hcPrimaryItem)
|
|
543
|
+
elrPrimaryItems["*"].add(hcPrimaryItem) # members of any ELR
|
|
544
|
+
hcPrimaryItems.clear()
|
|
545
|
+
hcMembers.clear()
|
|
546
|
+
return DimensionalData(
|
|
547
|
+
domainMembers=frozenset(domainMembers),
|
|
548
|
+
elrPrimaryItems=elrPrimaryItems,
|
|
549
|
+
primaryItems=frozenset(primaryItems),
|
|
550
|
+
)
|
|
426
551
|
|
|
427
552
|
def getEligibleForTransformHiddenFacts(self, modelXbrl: ModelXbrl) -> set[ModelInlineFact]:
|
|
428
553
|
return self.checkHiddenElements(modelXbrl).eligibleForTransformHiddenFacts
|
|
@@ -475,6 +600,7 @@ class PluginValidationDataExtension(PluginData):
|
|
|
475
600
|
def getIxdsDocBasenames(self, modelXbrl: ModelXbrl) -> set[str]:
|
|
476
601
|
return set(Path(url).name for url in getattr(modelXbrl, "ixdsDocUrls", []))
|
|
477
602
|
|
|
603
|
+
@lru_cache(1)
|
|
478
604
|
def getExtensionConcepts(self, modelXbrl: ModelXbrl) -> list[ModelConcept]:
|
|
479
605
|
"""
|
|
480
606
|
Returns a list of extension concepts in the DTS.
|
|
@@ -517,11 +643,36 @@ class PluginValidationDataExtension(PluginData):
|
|
|
517
643
|
for linkElt in modelDocument.xmlRootElement.iterdescendants(tag=linkbaseType.getLinkQn().clarkNotation):
|
|
518
644
|
arcQn = linkbaseType.getArcQn()
|
|
519
645
|
arcs = list(linkElt.iterdescendants(tag=arcQn.clarkNotation))
|
|
646
|
+
prohibitingLabelElements = []
|
|
647
|
+
prohibitedBaseConcepts = []
|
|
648
|
+
if linkbaseType in (LinkbaseType.LABEL, LinkbaseType.REFERENCE):
|
|
649
|
+
prohibitedArcFroms = defaultdict(list)
|
|
650
|
+
prohibitedArcTos = defaultdict(list)
|
|
651
|
+
for arcElt in linkElt.iterchildren(
|
|
652
|
+
LinkbaseType.LABEL.getArcQn().clarkNotation,
|
|
653
|
+
LinkbaseType.REFERENCE.getArcQn().clarkNotation,
|
|
654
|
+
):
|
|
655
|
+
if arcElt.get("use") == "prohibited":
|
|
656
|
+
prohibitedArcFroms[arcElt.get(XbrlConst.qnXlinkFrom.clarkNotation)].append(arcElt)
|
|
657
|
+
prohibitedArcTos[arcElt.get(XbrlConst.qnXlinkTo.clarkNotation)].append(arcElt)
|
|
658
|
+
for locElt in linkElt.iterchildren(XbrlConst.qnLinkLoc.clarkNotation):
|
|
659
|
+
if self.isExtensionUri(locElt.get(XbrlConst.qnXlinkHref.clarkNotation), modelDocument.modelXbrl):
|
|
660
|
+
continue
|
|
661
|
+
prohibitingArcs = prohibitedArcTos.get(locElt.get(XbrlConst.qnXlinkLabel.clarkNotation))
|
|
662
|
+
if prohibitingArcs:
|
|
663
|
+
prohibitingLabelElements.extend(prohibitingArcs)
|
|
664
|
+
prohibitingArcs = prohibitedArcFroms.get(locElt.get(XbrlConst.qnXlinkLabel.clarkNotation))
|
|
665
|
+
if prohibitingArcs:
|
|
666
|
+
prohibitingLabelElements.extend(prohibitingArcs)
|
|
667
|
+
prohibitedBaseConcepts.append(locElt.dereference())
|
|
668
|
+
|
|
520
669
|
linkbases.append(LinkbaseData(
|
|
521
670
|
arcs=arcs,
|
|
522
671
|
basename=modelDocument.basename,
|
|
523
672
|
element=linkElt,
|
|
524
673
|
linkbaseType=linkbaseType,
|
|
674
|
+
prohibitedBaseConcepts=prohibitedBaseConcepts,
|
|
675
|
+
prohibitingLabelElements=prohibitingLabelElements,
|
|
525
676
|
))
|
|
526
677
|
return linkbases
|
|
527
678
|
|
|
@@ -7,30 +7,36 @@
|
|
|
7
7
|
names="NL-INLINE-2024|nl-inline-2024|kvk-inline-2024-preview"
|
|
8
8
|
description="Checks for NL INLINE 2024. For use with NL GAAP and NL IFRS"
|
|
9
9
|
validationType="NL"
|
|
10
|
+
exclusiveTypesPattern="EFM|GFM|FERC|HMRC|SBR.NL|EBA|EIOPA|ESEF"
|
|
10
11
|
/>
|
|
11
12
|
<DisclosureSystem
|
|
12
13
|
names="NL-INLINE-2024-GAAP-OTHER|nl-inline-2024-gaap-other|kvk-inline-2024-gaap-other-preview"
|
|
13
14
|
description="Checks for NL INLINE 2024. For use with other GAAP."
|
|
14
15
|
validationType="NL"
|
|
16
|
+
exclusiveTypesPattern="EFM|GFM|FERC|HMRC|SBR.NL|EBA|EIOPA|ESEF"
|
|
15
17
|
/>
|
|
16
18
|
<DisclosureSystem
|
|
17
19
|
names="NT19|nt19|NT19-preview|nt19-preview"
|
|
18
20
|
description="Checks for NT19"
|
|
19
21
|
validationType="NL"
|
|
22
|
+
exclusiveTypesPattern="EFM|GFM|FERC|HMRC|SBR.NL|EBA|EIOPA|ESEF"
|
|
20
23
|
/>
|
|
21
24
|
<DisclosureSystem
|
|
22
25
|
names="NT18|nt18|NT18-preview|nt18-preview"
|
|
23
26
|
description="Checks for NT18"
|
|
24
27
|
validationType="NL"
|
|
28
|
+
exclusiveTypesPattern="EFM|GFM|FERC|HMRC|SBR.NL|EBA|EIOPA|ESEF"
|
|
25
29
|
/>
|
|
26
30
|
<DisclosureSystem
|
|
27
31
|
names="NT17|nt17|NT17-preview|nt17-preview"
|
|
28
32
|
description="Checks for NT17"
|
|
29
33
|
validationType="NL"
|
|
34
|
+
exclusiveTypesPattern="EFM|GFM|FERC|HMRC|SBR.NL|EBA|EIOPA|ESEF"
|
|
30
35
|
/>
|
|
31
36
|
<DisclosureSystem
|
|
32
37
|
names="NT16|nt16|NT16-preview|nt16-preview"
|
|
33
38
|
description="Checks for NT16"
|
|
34
39
|
validationType="NL"
|
|
40
|
+
exclusiveTypesPattern="EFM|GFM|FERC|HMRC|SBR.NL|EBA|EIOPA|ESEF"
|
|
35
41
|
/>
|
|
36
42
|
</DisclosureSystems>
|
|
@@ -120,7 +120,7 @@ def rule_fr_kvk_2_02(
|
|
|
120
120
|
if fact.xmlLang and fact.xmlLang != lang:
|
|
121
121
|
yield Validation.error(
|
|
122
122
|
codes='NL.FR-KVK-2.02',
|
|
123
|
-
msg=_('The attribute \'xml:lang\' can be reported on different elements within an XBRL instance document.'
|
|
123
|
+
msg=_('The attribute \'xml:lang\' can be reported on different elements within an XBRL instance document. '
|
|
124
124
|
'The attribute \'xml:lang\' must always contain the same value within an XBRL instance document. '
|
|
125
125
|
'It is not allowed to report different values here. Document language: %(documentLang)s Element language: %(additionalLang)s'),
|
|
126
126
|
modelObject=fact,
|