Presentar un sitio web en muchas ocasiones resulta una complicación cuando nos encontramos ante la posibilidad de personas de distintas culturas accediendo al mismo.
En muchas ocasiones no es sólo que el usuario lo indique sino también que el sitio sea capaz de reaccionar a la configuración que el navegador tenga.
Esto puede ser más complejo utilizando MOSS que, en forma predeterminada, permite asignar un idioma por sitio.
Sin embargo, MOSS no hace más que, como cualquier aplicación ASP.Net 2.0, acceder a archivos de recursos que, claro, deben estar instalados en el servidor (los paquetes de idioma de MOSS).
Dichos archivos de recursos se seleccionan dependiendo de la cultura del HILO de ejecución.
Entonces, si cambiamos dicha información, podemos alterar el comportamiento.
Lo importante es hacerlo ANTES que la página comience a generarse. Esto es, en el evento Init de la misma, y no en el Load.
Entonces, podríamos obtener que configuración tiene el navegador
<script runat="server">
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
Dim cult As String
cult = Page.Request.ServerVariables("HTTP_ACCEPT_LANGUAGE").ToString
Ahora bien, puede suceder que la cultura retornada por el navegador, sea genérica, cosa que no es aceptada como cultura de un hilo de ejecución.
Pongamos una solución simple, al solo efecto de este ejemplo.
Select Case cult
Case "es"
cult = "es-ES"
Case "en"
cult = "en-US"
End Select
Ahora bien, también es posible que ya el usuario esté navegando por el sitio, entonces podríamos tener su cultura en sesión (que siempre diga que no se debe usar la sesión para guardar todo, no significa que no se pueda usar para absolutamente nada :)). Entonces, mejor averigüemos si ya la tenemos antes de comenzar a ejecutar código
If Session("CultureInfo") Is Nothing Then
También podría ser que el usuario ya haya estado en nuestro sitio, y que dispongamos de mecanismos para que pueda seleccionar el idioma. Esa información bien podría estar en un cookie en su propio navegador.
Evaluemos entonces si es ese el caso:
If Page.Request.Cookies("UserCulture") IsNot Nothing Then
Dim cultcook As String = Page.Request.Cookies("UserCulture").Value.ToString
If cult <> cultcook AndAlso cultcook <> "" Then
cult = cultcook
End If
Además, si el usuario está autenticado, el propio MOSS podría tener almacenada l información de la cultura que el usuario desea en el perfil del mismo.
En ese caso, accederíamos a dicha información
If Me.Page.User.Identity.IsAuthenticated Then
Dim w As SPWeb = SPContext.Current.Web
'Obtenemos la configuración del perfil
' Esta clase manipula el perfil completo del usuario
Dim prof As New Solid.MOSS.Controls.ProfileMgmt(w.CurrentUser.Name)
Dim CultProf As String = prof.GetValue("CultureInfo")
If CultProf <> "" Then
cult = CultProf
Nota: El código de ProfileMgmt no se encuentra n el ejemplo, pero os lo podéis imaginar fácilmente. Y si no, pues ya vendrá en próxima entrega :)
Finalmente, guardamos esa configuración en sesión, para la próxima página.
Además, si ya la tenemos en sesión, utilizamos esa
Session("CultureInfo") = cult
Else
cult = Session("CultureInfo").ToString
Finalmente, creamos la cultura basada en esa configuración y la asignamos al hilo de ejecución.
Dim c As New System.Globalization.CultureInfo(cult)
System.Threading.Thread.CurrentThread.CurrentUICulture = c
System.Threading.Thread.CurrentThread.CurrentCulture = c
End Sub
</script>
Quienes me conocen saben de mi circular por la vida sobre una silla de ruedas.
Hay muchas limitaciones en ello (otro día hablaré en detalle), pero si además de las ya existentes, la gente no colabora, bien poco es lo que se puede disfrutar de la vida.
Tengo varias, pero como para no saturar (y hacerlo más entretenido), van a ir apareciendo de a una.
Mi idea es mostrarles que poco considerada es la gente a veces (o que ridículas las soluciones que algunos plantean), en esto de ayudar al discapacitado (que el término "minusválido" utilizado en España no me parece adecuado).
Esto fue, circulando (bueno, tratando de circular :) ) por Ourense, el 5 de julio del 2008.
Parece que el conductor no se da cuenta que si se estaciona así, ni modo que una silla de ruedas pueda subir.
Saludos
Yo sé que te tuviste que ir... Pero no me gusta nada. Sé que ibas a sufrir y que es mejor que haya sido así.
Pero no puedo dejar de estar triste. Porque me acompañaste durante una parte difícil de mi devenir por el mundo. Porque fuiste quien me escuchaba, pacientemente, sin entender pero sintiendo que era lo que tenía en mi alma.
Porque fuiste el motivo de miles de sonrisas en el bello rostro de "mamá" y eso es algo que siempre me alegra el corazón.
No sabés cuanto bien me hizo siempre tu compañía, cuando las cosas se ponían difíciles y debía quedarme horas y horas y hasta noches enteras sin dormir... y vos ahí, conmigo, siempre.
O cuando me sacabas la mano del ratón porque era hora de jugar... y cuantas veces me sacaste así de la bronca por algo que no me salía :)
Me había imaginado en unos años, con vos ahí, con nosotros, haciéndonos compañía.
Te llamé Huan porque eras quien venía a acompañar y a alegrar la vida de los humanos. Gracias, porque realmente lo hiciste.
Si ya sé que no querés que estemos tristes... 'pero también date cuenta, que no es fácil saber que no estarás...
Y que hay cosas que nunca pude hacer con vos, como sacarte a pasear, o jugar al aire libre... porque ni vos ni yo teníamos todas de nuestro lado.
Sólo nos acompañaste tres años. Pero nos hiciste sentir que eras feliz.
Ojalá hayas podido sentir que te queríamos así
Adiós mi amigo... hasta siempre
InfoPath como aplicación es capaz de generar documentos XML que contienen no solo la información también la estructura del mismo.
Utilizando la herramienta XSD.exe es posible generar una clase que facilite manipular dicha información (http://msdn.microsoft.com/en-us/library/bb251017.aspx). Sin embargo, es específica para cada documento.
En muchas oportunidades sucede que se requiere codificar (por ejemplo un flujo de trabajo), para múltiples documentos y formatos.
Para facilitar estas actividades, se me ocurrió definir una clase que administre genéricamente el contenido de documentos InfoPath.
Esta clase recibe un elemento de una biblioteca de documentos InfoPath de SharePoint y carga el documento en memoria para facilitar su manipulación.
Comencemos con la lista de importaciones y variables necesarias.
Imports System.Xml.Serialization Imports System.Xml ''' <summary> ''' Permite manipular el contenido de un documento de InfoPath en algo fácilmente accesible por código ''' </summary> ''' <remarks>Carga el contenido del documento, adjunto a una biblioteca de documentos de MOSS ''' y crea listas fácilmente accesibles tanto de los atributos como de los valores (elementos) ''' </remarks> Public Class InfoPathConverter ''' <summary> ''' Documento conteniendo todo el documento InfoPath ''' </summary> ''' <remarks></remarks> Dim xDoc As XDocument = Nothing ''' <summary> ''' Lista de atributos ''' </summary> ''' <remarks></remarks> Dim atrs As Dictionary(Of String, XAttribute) ''' <summary> ''' lista de valores (elementos) ''' </summary> ''' <remarks></remarks> Dim els As Dictionary(Of String, XElement)
Imports System.Xml.Serialization
Imports System.Xml
''' <summary>
''' Permite manipular el contenido de un documento de InfoPath en algo fácilmente accesible por código
''' </summary>
''' <remarks>Carga el contenido del documento, adjunto a una biblioteca de documentos de MOSS
''' y crea listas fácilmente accesibles tanto de los atributos como de los valores (elementos)
''' </remarks>
Public Class InfoPathConverter
''' Documento conteniendo todo el documento InfoPath
''' <remarks></remarks>
Dim xDoc As XDocument = Nothing
''' Lista de atributos
Dim atrs As Dictionary(Of String, XAttribute)
''' lista de valores (elementos)
Dim els As Dictionary(Of String, XElement)
Una de las características que me suelen ser necesarias es la de asegurarme que existan ciertas propiedades y atributos en el documento ya que son utilizados en la lógica del flujo.
Por ello, la clase expone 2 propiedades para contener los atributos y los campos que son requeridos.
''' <summary> ''' Lista de nombres de atributos requeridos en el documento ''' </summary> ''' <remarks></remarks> Private mAtributes As List(Of String) ''' <summary> ''' Define que atributos son necesarios en el documento para considerarlo válido ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property AttributesNeeded() As List(Of String) Get If mAtributes Is Nothing Then mAtributes = New List(Of String) mAtributes.Add("Etapa") End If Return mAtributes End Get End Property Private mFieldsNeeded As List(Of String) ''' <summary> ''' Define que campos son necesarios en el documento para considerarlo válido ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property FieldsNeeded() As List(Of String) Get If mFieldsNeeded Is Nothing Then mFieldsNeeded = New List(Of String) End If Return mFieldsNeeded End Get End Property
''' Lista de nombres de atributos requeridos en el documento
Private mAtributes As List(Of String)
''' Define que atributos son necesarios en el documento para considerarlo válido
''' <value></value>
''' <returns></returns>
Public ReadOnly Property AttributesNeeded() As List(Of String)
Get
If mAtributes Is Nothing Then
mAtributes = New List(Of String)
mAtributes.Add("Etapa")
Return mAtributes
End Get
End Property
Private mFieldsNeeded As List(Of String)
''' Define que campos son necesarios en el documento para considerarlo válido
Public ReadOnly Property FieldsNeeded() As List(Of String)
If mFieldsNeeded Is Nothing Then
mFieldsNeeded = New List(Of String)
Return mFieldsNeeded
''' <summary> ''' Carga en las listas el contenido del documento InfoPath ''' </summary> ''' <param name="item">Item de la biblioteca de docuemntos, conteniendo el mismo</param> ''' <remarks>Carga el contenido del documento, adjunto a una biblioteca de documentos de MOSS ''' y crea listas fácilmente accesibles tanto de los atributos como de los valores (elementos) ''' </remarks> Sub getDocumentContent(ByVal item As SPListItem) 'La propiedad File expone el documento InfoPath Dim xtextr As New XmlTextReader(item.File.OpenBinaryStream) 'Se carga entonces el documento desde el Stream xDoc = XDocument.Load(xtextr) 'Obtiene los atributos atrs = (From x As XAttribute In xDoc.Root.Attributes).ToDictionary( _ Of String)(Function(x) x.Name.LocalName.ToUpper) ' Evalúa si todos los atributos requeridos están pesentes For Each s As String In AttributesNeeded Dim lookFor As String = s.ToUpper If (From a As XAttribute In atrs.Values _ Where a.Name.LocalName.ToUpper = lookFor).ToArray.Length < 1 Then Throw New Exception("Formulario inválido: le falta el atributo " & s) End If Next ' Evalúa lo mismo para los campos (Elements) els = (From v As XElement In xDoc.Root.Elements).ToDictionary( _ Of String)(Function(v) v.Name.LocalName.ToUpper) For Each s As String In FieldsNeeded Dim lookFor As String = s.ToUpper If (From a As XElement In els.Values _ Where a.Name.LocalName.ToUpper = lookFor).ToArray.Length < 1 Then Throw New Exception("Formulario inválido: le falta el campo " & s) End If Next End Sub Teniendo el documento en memoria, se pueden exponer los valores y asignarles nuevos con estos métodos: ''' <summary> ''' Cambia el valor de un atributo ''' </summary> ''' <param name="what">Nombre del atributo</param> ''' <param name="newValue">Nuevo Valor</param> ''' <remarks></remarks> Sub ChangeAttribute(ByVal what As String, ByVal newValue As String) If atrs.ContainsKey(what.ToUpper) Then atrs(what.ToUpper).Value = newValue End If End Sub ''' <summary> ''' Obtiene el valor de uhn atributo ''' </summary> ''' <param name="what">Nombre del atirbuto</param> ''' <returns>Contenido del mismo (siempr como cadena de caracteres) o valor nulo si no existe ''' </returns> ''' <remarks></remarks> Function ReadAttribute(ByVal what As String) As String If atrs.ContainsKey(what.ToUpper) Then Return atrs(what.ToUpper).Value Else Return Nothing End If End Function ''' <summary> ''' Cambia el valor de un elemento ''' </summary> ''' <param name="what">Nombre del elemento</param> ''' <param name="newValue">Valor a asignar</param> ''' <remarks></remarks> Sub ChangeValue(ByVal what As String, ByVal newValue As String) If els.ContainsKey(what.ToUpper) Then els(what.ToUpper).Value = newValue End If End Sub ''' <summary> ''' Obtiene le valor de un elemento ''' </summary> ''' <param name="what">Nombre del elemento a leer</param> ''' <returns>Valor del elemento (siempre como cadena de caracteres), o valor nulo si no existe ''' </returns> ''' <remarks></remarks> Function ReadValue(ByVal what As String) As String If els.ContainsKey(what.ToUpper) Then Return els(what.ToUpper).Value Else Throw New KeyNotFoundException("El campo " & what & " no se encuentra en el documento") End If End Function
''' Carga en las listas el contenido del documento InfoPath
''' <param name="item">Item de la biblioteca de docuemntos, conteniendo el mismo</param>
Sub getDocumentContent(ByVal item As SPListItem)
'La propiedad File expone el documento InfoPath
Dim xtextr As New XmlTextReader(item.File.OpenBinaryStream)
'Se carga entonces el documento desde el Stream
xDoc = XDocument.Load(xtextr)
'Obtiene los atributos
atrs = (From x As XAttribute In xDoc.Root.Attributes).ToDictionary( _
Of String)(Function(x) x.Name.LocalName.ToUpper)
' Evalúa si todos los atributos requeridos están pesentes
For Each s As String In AttributesNeeded
Dim lookFor As String = s.ToUpper
If (From a As XAttribute In atrs.Values _
Where a.Name.LocalName.ToUpper = lookFor).ToArray.Length < 1 Then
Throw New Exception("Formulario inválido: le falta el atributo " & s)
Next
' Evalúa lo mismo para los campos (Elements)
els = (From v As XElement In xDoc.Root.Elements).ToDictionary( _
Of String)(Function(v) v.Name.LocalName.ToUpper)
For Each s As String In FieldsNeeded
If (From a As XElement In els.Values _
Throw New Exception("Formulario inválido: le falta el campo " & s)
Teniendo el documento en memoria, se pueden exponer los valores y asignarles nuevos con estos métodos:
''' Cambia el valor de un atributo
''' <param name="what">Nombre del atributo</param>
''' <param name="newValue">Nuevo Valor</param>
Sub ChangeAttribute(ByVal what As String, ByVal newValue As String)
If atrs.ContainsKey(what.ToUpper) Then
atrs(what.ToUpper).Value = newValue
''' Obtiene el valor de uhn atributo
''' <param name="what">Nombre del atirbuto</param>
''' <returns>Contenido del mismo (siempr como cadena de caracteres) o valor nulo si no existe
''' </returns>
Function ReadAttribute(ByVal what As String) As String
Return atrs(what.ToUpper).Value
Return Nothing
End Function
''' Cambia el valor de un elemento
''' <param name="what">Nombre del elemento</param>
''' <param name="newValue">Valor a asignar</param>
Sub ChangeValue(ByVal what As String, ByVal newValue As String)
If els.ContainsKey(what.ToUpper) Then
els(what.ToUpper).Value = newValue
''' Obtiene le valor de un elemento
''' <param name="what">Nombre del elemento a leer</param>
''' <returns>Valor del elemento (siempre como cadena de caracteres), o valor nulo si no existe
Function ReadValue(ByVal what As String) As String
Return els(what.ToUpper).Value
Throw New KeyNotFoundException("El campo " & what & " no se encuentra en el documento")
Finalmente ento0nces, con un método Save, se puede guardar en la lista de origen... o en otra. Para ello, se le envía al método el ListItem que contendrá el documento.
''' <summary> ''' Guarda el contenido de los valores y atributos en el documento InfoPath actualizando los mismos ''' </summary> ''' <param name="item"></param> ''' <remarks></remarks> Public Sub Save(ByVal item As SPListItem) item.File.CheckOut() Dim memoryStream As New IO.MemoryStream() Dim sett As New XmlWriterSettings sett.Encoding = System.Text.Encoding.UTF8 sett.OmitXmlDeclaration = False Dim xmlTextWriter As XmlWriter = XmlWriter.Create(memoryStream, sett) xDoc.Save(xmlTextWriter) xmlTextWriter.Flush() memoryStream.Position = 0 item.File.SaveBinary(memoryStream.GetBuffer) item.File.CheckIn("") End Sub
''' Guarda el contenido de los valores y atributos en el documento InfoPath actualizando los mismos
''' <param name="item"></param>
Public Sub Save(ByVal item As SPListItem)
item.File.CheckOut()
Dim memoryStream As New IO.MemoryStream()
Dim sett As New XmlWriterSettings
sett.Encoding = System.Text.Encoding.UTF8
sett.OmitXmlDeclaration = False
Dim xmlTextWriter As XmlWriter = XmlWriter.Create(memoryStream, sett)
xDoc.Save(xmlTextWriter)
xmlTextWriter.Flush()
memoryStream.Position = 0
item.File.SaveBinary(memoryStream.GetBuffer)
item.File.CheckIn("")
Si si, ya sé. quieres verlo completo. Pues aquí está la clase entera. http://blogs.solidq.com/ES/dseara/Archivos/InfoPathConverter.zip