DIN EN 14564:2025-09
Tanks for transport of dangerous goods - Terminology; German and English version prEN 14564:2025 / Note: Date of issue 2025-08-22*Intended as replacement for DIN EN 14564 (2019-10).
| Edition date: |
2025-09-01
In Force
|
|---|---|
| Available languages: | Alemán, English, FR |
| Summary: | This document provides additional terms and definitions to those written in the European Agreement Concerning the International Carriage of Dangerous Goods by Road (ADR) or the Regulations concerning the International Carriage of Dangerous Goods by Rail (RID), appearing as Appendix C to the Convention concerning International Carriage by Rail (COTIF). This document forms part of series of documents prepared by CEN/TC 296 regarding the transport of dangerous goods. The series supports the proper application of the ADR and RID. This document is applicable to tanks used for the transport of dangerous goods. This document does not apply to carriage in bulk of dangerous goods. For convenience, Annex A (informative) repeats some horizontal definitions taken from ADR 2017 chapter 1.2, and Annex B (informative) repeats some definitions from ADR 2017 chapter 6.7, specific to portable tanks. NOTE The ADR is updated on a regular basis, therefore Annexes A and B might become out of date. Annexes C, D and E (informative) provide alphabetical trilingual indexes of terms in English, French and German where the key is English, French and German respectively. Annex F (normative) is a schematic diagram of tank openings and closures according to the tank code. |
| Keywords: | Dangerous goods|Definitions|Pressure vessels|Tanks|Tanks (containers)|Terminology|Terminology standard|Transport|Transport of dangerous goods|Vocabulary |
| ICS: | 01.040.13-Environment and health protection. Safety (Vocabularies), 13.300-Protection against dangerous goods, 01.040.23-Fluid systems and components for general use Vocabularies), 23.020.20-Vessels and containers mounted on vehicles |
| CTN: |
An error occurred while processing the template.
The following has evaluated to null or missing:
==> languageEntries?filter(entry -> entry.key == keyValue)?first [in template "34352066712900#33336#null" at line 151, column 30]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign match = languageEntries?filte... [in template "34352066712900#33336#null" in function "addAllMatchingLanguagesByField" at line 151, column 13]
----
1<#-- Variables -->
2<#assign isDebug = false>
3<#assign channelResponse = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?filter=name eq 'Aenor Tienda'")>
4<#assign channel = channelResponse.items[0]>
5<#assign channelId = channel.id>
6<#assign product = getProduct(channelId, CPDefinition_cProductId.getData()) />
7<#assign siteGroup = themeDisplay.getSiteGroup() />
8<#assign currentLocale = themeDisplay.getLocale()>
9<#assign currentLanguage = currentLocale?substring(0,2)>
10
11<#-- Product data -->
12<#assign displayDateProduct = CPDefinition_displayDate.getData() />
13<#assign productId = product.productId />
14<#assign cpDefinitionId = product.id />
15
16<#assign categoriesProduct = getProductCategories(channelId, productId) />
17<#assign hasProductCategoriaTipoEntidadLibro = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'libro') />
18<#assign hasProductCategoriaTipoEntidadNorma = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'norma') />
19<#assign hasProductCategoriaTipoEntidadColeccionTematica = isVocabularyNameIntoCategories(categoriesProduct, 'entity type', 'coleccion tematica') />
20<#assign categoryProductInfoTematica = getCategoriesByVocabularyAsString(categoriesProduct, "temáticas", " / ", "title") />
21<#assign categoryProductInfoStatus = getCategoriesByVocabularyAsString(categoriesProduct, "status", " / ", "title") />
22
23<#-- PickList de languages -->
24<#assign ercOfListTypeEntryLanguages = 'IDIOMAS_NORMAS_PICKLIST' />
25<#assign languageEntries = getListTypeEntriesByERC(ercOfListTypeEntryLanguages) />
26
27<#-- Specifications/Specifications language -->
28<#assign specificationsLanguagesProduct = getSpecificationsProduct(channelId, productId, 'specificationKey', 'standard-languages') />
29<#assign filteredSpecificationsLanguagesProductTemp = filterOutItems(specificationsLanguagesProduct, 'value', ['BI', 'TR']) />
30<#assign filteredSpecificationsLanguagesProduct = addAllMatchingLanguagesByField(filteredSpecificationsLanguagesProductTemp, languageEntries, 'value', 'title') />
31
32<#-- Thematic collection/Coleccion tematica data -->
33<#assign thematicCollectionsProduct = getThematicCollectionProduct(cpDefinitionId) />
34
35
36<#-- Functions -->
37<#function getProduct channelId productId>
38 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}")>
39</#function>
40
41
42<#function getProductByERC erc>
43 <#-- TODO: estamos usando el endpoint del product admin, hay que usar la del Product de Liferay NO admin: headless-commerce-delivery-catalog -->
44 <#-- <#return restClient.get("/headless-commerce-admin-catalog/v1.0/products/by-externalReferenceCode/${erc}")> -->
45 <#assign response = restClient.get("/headless-commerce-admin-catalog/v1.0/products/by-externalReferenceCode/${erc}")>
46 <#-- Si el producto no existe o tiene status NOT_FOUND, devolvemos string vacío -->
47 <#if response?? && response.status?? && response.status == "NOT_FOUND">
48 <#return {}>
49 <#elseif !response??>
50 <#return {}>
51 <#else>
52 <#return response>
53 </#if>
54</#function>
55
56
57<#function getURLsOfProduct product baseURL="" siteFriendlyURL="" languageFieldName="language" urlFieldName="url">
58 <#-- Inicializamos un array vacío -->
59 <#assign urlsArray = []>
60
61 <#-- Validamos que product y product.urls existan -->
62 <#if product?? && product.urls??>
63 <#-- Iteramos sobre los idiomas -->
64 <#list product.urls?keys as lang>
65 <#assign urlValue = product.urls[lang] />
66 <#if urlValue?? && urlValue?has_content>
67 <#-- Aseguramos que la URL empiece con "/p/" -->
68 <#assign cleanUrl = urlValue?starts_with("/")?then(urlValue, "/p/" + urlValue) />
69
70 <#-- Generamos la URL completa -->
71 <#-- Si baseURL tiene contenido, construimos URL completa -->
72 <#if baseURL?? && baseURL?has_content>
73
74 <#-- Aseguramos que el slug empiece con /p/ -->
75 <#assign cleanUrl = urlValue?starts_with("/")?then(urlValue, "/p/" + urlValue) />
76
77 <#-- Tomamos las dos primeras letras del idioma para el prefijo -->
78 <#assign langPrefix = lang?substring(0,2)>
79
80 <#-- Construimos la URL completa -->
81 <#if siteFriendlyURL?? && siteFriendlyURL?has_content>
82 <#assign fullUrl = baseURL + "/" + langPrefix + siteFriendlyURL + cleanUrl>
83 <#else>
84 <#assign fullUrl = baseURL + "/" + langPrefix + cleanUrl>
85 </#if>
86
87 <#else>
88 <#assign fullUrl = cleanUrl>
89 </#if>
90
91 <#-- Creamos el objeto language+url -->
92 <#assign newItem = {(languageFieldName): lang, (urlFieldName): fullUrl} />
93
94 <#-- Lo agregamos al array -->
95 <#assign urlsArray = urlsArray + [newItem] />
96 </#if>
97 </#list>
98 </#if>
99
100 <#return urlsArray>
101</#function>
102
103
104<#function getProductCategories channelId productId>
105 <#return restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/categories?sort=vocabulary").items>
106</#function>
107
108
109<#function getSpecificationsProduct channelId productId field="" value="">
110 <#assign response = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/${channelId}/products/${productId}/product-specifications?pageSize=100&sort")>
111 <#assign items = response.items>
112
113 <#-- Si se pasa campo y valor, filtrar -->
114 <#if field?has_content && value?has_content>
115 <#assign items = items?filter(item ->
116 (item[field]??) && (item[field]?string?lower_case == value?lower_case)
117 )>
118 </#if>
119
120 <#return items>
121</#function>
122
123
124<#function filterOutItems items field valuesToExclude>
125 <#-- Si el array o los valores no existen, devolver items sin cambios -->
126 <#if !items?? || !valuesToExclude??>
127 <#return items>
128 </#if>
129
130 <#-- Filtramos: solo mantener los items cuyo campo no esté en la lista -->
131 <#assign filteredItems = items?filter(item ->
132 !(item[field]?? && (valuesToExclude?seq_contains(item[field]?string)))
133 )>
134
135 <#return filteredItems>
136</#function>
137
138
139<#function addAllMatchingLanguagesByField specificationsLanguagesProduct languageEntries specValueField newSpecField>
140
141 <#if specificationsLanguagesProduct?? && languageEntries?? && specValueField?? && newSpecField??>
142
143 <#-- Creamos una copia para no modificar el original directamente -->
144 <#assign updatedSpecs = []>
145
146 <#list specificationsLanguagesProduct as spec>
147 <#-- Buscar coincidencia -->
148 <#assign keyValue = spec[specValueField]>
149 <#assign match = languageEntries?filter(entry -> entry.key == keyValue)?first>
150
151 <#-- Crear una copia del objeto actual -->
152 <#assign newSpec = spec>
153
154 <#-- Si hay match con nombre válido, añadir el nuevo campo -->
155 <#if match?? && match.name?? && match.name?has_content>
156 <#assign newSpec = newSpec + { (newSpecField): match.name }>
157 </#if>
158
159 <#-- Añadir al array final -->
160 <#assign updatedSpecs = updatedSpecs + [newSpec]>
161 </#list>
162
163 <#return updatedSpecs>
164 <#else>
165 <#return specificationsLanguagesProduct>
166 </#if>
167</#function>
168
169
170<#function getListTypeEntriesByERC erc fields="key,name,externalReferenceCode,name_i18n" sort="key" pageSize="1000">
171 <#attempt>
172 <#return restClient.get(
173 "/headless-admin-list-type/v1.0/list-type-definitions/by-external-reference-code/${erc}/list-type-entries?fields=${fields}&sort=${sort}&pageSize=${pageSize}"
174 ).items>
175 <#recover>
176 <#return []>
177 </#attempt>
178</#function>
179
180
181<#function getThematicCollectionProduct cpDefinitionId>
182 <#assign response = restClient.get("/c/thematiccollections/?filter=r_thematicCollection_CPDefinitionId eq '${cpDefinitionId}'")!{} />
183 <#assign items = response.items![] />
184 <#return (items?size > 0)?then(items[0], {}) />
185</#function>
186
187
188<#function sortByField items fieldPath sortFieldName="sortKey" order="asc">
189
190 <#-- Array temporal con el campo auxiliar -->
191 <#assign prepared = []>
192
193 <#list items as e>
194 <#-- Evaluar el valor del campo dinámico -->
195 <#assign sortValue = "" />
196 <#if fieldPath == "section?first.key">
197 <#assign sortValue = (e.section?first.key)!""?lower_case>
198 <#elseif fieldPath == "section?first.name">
199 <#assign sortValue = (e.section?first.name)!""?lower_case>
200 <#elseif fieldPath == "type?first.key">
201 <#assign sortValue = (e.type?first.key)!""?lower_case>
202 <#else>
203 <#-- Si el campoPath no está mapeado, usar vacío -->
204 <#assign sortValue = "" />
205 </#if>
206
207 <#-- Agregar objeto enriquecido con campo auxiliar -->
208 <#assign prepared = prepared + [ e + { (sortFieldName): sortValue } ]>
209 </#list>
210
211 <#-- Ordenar -->
212 <#assign sorted = prepared?sort_by(sortFieldName)>
213
214 <#-- Si order = desc, invertir -->
215 <#if order?lower_case == "desc">
216 <#assign sorted = sorted?reverse>
217 </#if>
218
219 <#return sorted>
220</#function>
221
222
223<#function addKeysFieldNested items arrayField nestedField newFieldName mode="first" subArrayField="">
224
225 <#assign enrichedItems = []>
226
227 <#list items as e>
228 <#assign resultValue = "">
229
230 <#-- Detectamos el array del objeto principal -->
231 <#assign targetArray = e[arrayField]![]>
232
233 <#if targetArray?has_content>
234 <#if mode == "all">
235 <#assign keysList = []>
236 <#list targetArray as t>
237 <#if subArrayField?has_content>
238 <#assign subArray = t[subArrayField]![]>
239 <#if subArray?has_content>
240 <#list subArray as sub>
241 <#assign keysList = keysList + [ sub[nestedField]!"" ]>
242 </#list>
243 </#if>
244 <#else>
245 <#assign keysList = keysList + [ t[nestedField]!"" ]>
246 </#if>
247 </#list>
248 <#assign resultValue = keysList?join(", ")>
249 <#elseif mode == "first">
250 <#assign firstItem = targetArray?first>
251 <#if subArrayField?has_content>
252 <#assign subArray = firstItem[subArrayField]![]>
253 <#if subArray?has_content>
254 <#assign resultValue = subArray?first[nestedField]!"" >
255 <#else>
256 <#assign resultValue = "" >
257 </#if>
258 <#else>
259 <#assign resultValue = firstItem[nestedField]!"" >
260 </#if>
261 </#if>
262 <#else>
263 <#assign resultValue = "">
264 </#if>
265
266 <#-- Añadimos el nuevo campo al objeto -->
267 <#assign enrichedItems = enrichedItems + [
268 e + { (newFieldName): resultValue }
269 ]>
270 </#list>
271
272 <#return enrichedItems>
273</#function>
274
275
276<#function isVocabularyNameIntoCategories categories vocabulary name>
277 <#assign found = false />
278
279 <#if categories?has_content && vocabulary?has_content && name?has_content>
280
281 <#assign vocabNorm = normalize(vocabulary) />
282 <#assign nameNorm = normalize(name) />
283
284 <#list categories as category>
285 <#if !found>
286 <#assign catVocabNorm = normalize(category.vocabulary) />
287 <#assign catNameNorm = normalize(category.name) />
288
289 <#if catVocabNorm == vocabNorm && catNameNorm == nameNorm>
290 <#assign found = true />
291 </#if>
292 </#if>
293 </#list>
294
295 </#if>
296
297 <#return found>
298</#function>
299
300
301<#function normalize text onlyAccents = false>
302 <#-- proteger null -->
303 <#if !text?has_content>
304 <#return "">
305 </#if>
306
307 <#assign t = text />
308
309 <#-- quitar acentos -->
310 <#assign t = t
311 ?replace("á","a")?replace("é","e")?replace("í","i")
312 ?replace("ó","o")?replace("ú","u")?replace("ü","u")
313 ?replace("ñ","n")
314 ?replace("Á","A")?replace("É","E")?replace("Í","I")
315 ?replace("Ó","O")?replace("Ú","U")?replace("Ü","U")
316 ?replace("Ñ","N")
317 />
318
319 <#-- si NO es solo acentos, normalización completa -->
320 <#if !onlyAccents>
321 <#assign t = t?lower_case />
322 <#assign t = t?trim />
323 <#assign t = t?replace("\\s+", " ", "r") />
324 </#if>
325
326 <#return t>
327</#function>
328
329
330<#-- Función que retorna los valores de categorías como string, normalizando vocabulario -->
331<#function getCategoriesByVocabularyAsString categories vocabulary separator=" / " field="name">
332 <#assign matchedValues = []>
333 <#if categories?has_content && vocabulary?has_content>
334 <#list categories as category>
335 <#-- Normalizamos tanto el vocabulary de la categoría como el buscado -->
336 <#if normalize(category.vocabulary, true)?lower_case == normalize(vocabulary, true)?lower_case>
337 <#if field == "title">
338 <#assign matchedValues += [category.title]>
339 <#else>
340 <#assign matchedValues += [category.name]>
341 </#if>
342 </#if>
343 </#list>
344 </#if>
345 <#return matchedValues?join(separator)>
346</#function>
347
348
349<#macro printObject obj>
350 <#-- Permite hacer un output de un array de objetos o un objeto que se pasa como parámetro -->
351 <#if obj?is_hash>
352 {
353 <#list obj?keys as k>
354 "${k}":
355 <#assign value = obj[k]>
356 <#if value?is_hash || value?is_sequence>
357 <@printObject obj=value/>
358 <#elseif value?is_boolean>
359 ${value?c}
360 <#elseif value?is_number>
361 ${value}
362 <#elseif value?has_content>
363 "${value?string}"
364 <#else>
365 null
366 </#if>
367 <#if k_has_next>, </#if>
368 </#list>
369 }
370 <#elseif obj?is_sequence>
371 [
372 <#list obj as item>
373 <@printObject obj=item/>
374 <#if item_has_next>, </#if>
375 </#list>
376 ]
377 <#elseif obj?is_boolean>
378 ${obj?c}
379 <#elseif obj?is_number>
380 ${obj}
381 <#elseif obj?has_content>
382 "${obj?string}"
383 <#else>
384 null
385 </#if>
386</#macro>
387
388
389
390
391<#-- HTML -->
392<#if hasProductCategoriaTipoEntidadColeccionTematica>
393 <div id="ecom-coleccion_tematica-detail" class="ecom-coleccion_tematica">
394
395 <div class="tabs-section">
396 <div class="tab-content">
397
398 <#-- Fecha edicion del producto > description del Producto -->
399 <div class="ecom-coleccion_tematica-detail-body">
400 ${product.description}
401 </div>
402
403 <#-- Para imprimir el contenido de los Objects -->
404 <#-- Thematic collection/Coleccion tematica data
405 <#if isDebug>
406 <div class="">
407 <p><strong>thematicCollectionsProduct:</strong></p>
408 <div class="print-object-json-content mb-3" style="max-height:200px; overflow:auto; border:1px solid #ccc; padding:5px; cursor:pointer;"
409 onclick="const r=document.createRange(); r.selectNodeContents(this); const s=window.getSelection(); s.removeAllRanges(); s.addRange(r);">
410 <@printObject thematicCollectionsProduct />
411 </div>
412 </div>
413 </#if>
414 -->
415
416 </div>
417 </div>
418 </div>
419</#if>










