iOS Localization of Server Provided Strings - ios

I need to figure out what is the standard/best practice for displaying localized UI text in an iOS from text that is received from a remote source, such as API driven, server-provided text. iOS Localization of static text is not a problem and we already have a system for managing that.
It seems to me the right and best thing would be to have the translated text sent by the server and displayed as received on the app, but there are some concerns about doing it this way, such as the app's locale/current language being possibly different than the current settings on the server. This presents the possibility that there may be a mismatch in dialect or language between what the phone is currently set to and what the server is set to. Also, we are considering how having the server do this breaks any of the S.O.L.I.D. design principles.
So, it comes to two possibilities. Either the server provides the translated text or the app does.
We could possibly provide a parameter to the server that would indicate which locale the device is set to (ie "en-us"). I imagine that this would be sent as an HTTP request header parameter.
It has also been suggested that the mobile app provide similar functionality for itself. This would involve maintaining a data store of some kind (tbd) so that display strings would be given to a facade and translated strings would be returned. ie: func translate(uiText: String) -> String. Internally, it could determine the user's locale and use that as part of the query needed to select the correct translated text. Again, the implementation of this would have to be decided, but that's not the problem I'm hoping to find a solution for.
To sum it up, what I really need is to know what is standard practice for translating server provided text that is to be displayed to the user and are there any frameworks out there designed to assist with this requirement (assuming the solution should exist in the mobile app)?
It seems to me that this is functionality best provided by the server. Also note that we have an Android app that would require similar enhancement.

I think I found a solution to this question but I do not want to mark it as the accepted answer unless I can get some feedback reinforcing what I have learned.
Most of the research I've done has lead me to what works for Web development, which is similar because it's still development but a much different creature than mobile. Mobile is compiled, which makes the advantages and disadvantages of where to do the presentation logic balance a little differently.
Some sources said it belongs on the server where it came from. Some sources said the client should do it. (I'll post references at the end.)
I opened up a discussion amongst my colleagues on the topic and this is where I found what I think will be our best solution. (Comments and criticisms are certainly welcome.)
I'll refer to data provided by the server through the API here forth as just "server".
For every string that the server provides that is meant to be displayed in the UI, I need to have some way to define these strings statically in the iOS app. Ideally I think an enum per display string would work. I can wrap every string with NSLocalizedString in the definition of the enum. Make the enum a String type, and initialize an instance of the enum from the string received from the server. The enum will return the NSLocalizedString. The iOS Localization system should export all of those localized strings, I will receive translations, and they will then exist in the various respective .strings files.
EG:
enum Emotion: String {
case happy = "Happy"
case sad = "Sad"
case angry = "Angry"
case joy = "Joy"
case amused = "Amused"
case bored = "Bored"
case undefined = ""
func translation() -> String {
switch self {
case .happy:
return NSLocalizedString("Happy", comment: "Happy")
case .sad:
return NSLocalizedString("Sad", comment: "Sad")
case .angry:
return NSLocalizedString("Angry", comment: "Angry")
case .joy:
return NSLocalizedString("Joy", comment: "Joy")
case .amused:
return NSLocalizedString("Amused", comment: "Amused")
case .bored:
return NSLocalizedString("Bored", comment: "Bored")
default:
return "--"
}
}
}
Implementation:
let thisCameFromTheServer: String? = "Happy"
let emo = Emotion(rawValue: thisCameFromTheServer ?? "") ?? .undefined
References
https://softwareengineering.stackexchange.com/questions/313726/where-should-i-do-localization-server-side-or-client-side
https://softwareengineering.stackexchange.com/questions/373395/api-internationalization
https://www.appliedis.com/localization-of-xcode-ios-apps-part-1/

Related

iOS: AppIntent parameter supporting multiple types of data?

I currently have 3 AppIntents that each support different kinds of input data. I'd prefer to have a single AppIntent that can receive anything - similar to the AirDrop shortcut action.
I know I can create an AppEntity with custom data, but I'm looking for input from a previous action/variable, not something defined within my app, so it doesn't seem applicable.
AppEnum doesn't work, because it requires a static display representation.
I've tried Any, AnyObject, and enum to no success.
Is this possible?

How to get via Organisation service for Microsoft Dynamics the OptionSet value and Formatted value in different languages?

I have a custom .NET application to query and managing data on a Microsoft Dynamics CRM instance.
This application is multilingual and the user can change via a language switch the language of the application.
For the connection and actions I'm using the OrganizationService and CRMServiceClient from Microsoft.Xrm.Sdk. This is combined with dependency injection to pass the connection to our different classes.
With Ninject this bindings look like
Bind().To().WithConstructArgument("crmConnectionString","the connection string");
Querying and updating the data in Dynamics is working but we are not able to retrieve the OptionSet values and Formatted values in the language the visitor have selected in the custom app. This is always in the same language even when we change the culture for the Thread before we call Dynamics.
How can we pass the current language / culture to the OrganizationService so that it knows in what language it have to retrieve the fields?
Someone told me that this is based on the account used to connect to the CRM. So if that's indeed the case then it means that if we have 5 languages that we need to have 5 connection strings and 5 OrgnaizationService instances that need to be called. How should I handle this in a good way in that case?
Thanks for your answers
The solution I implemented was to use CallerId.
Before returning the client I fill the CallerId with a Guid.
The Guid is from a user configured with a specific language in Dynamics.
Based on the language I take a different user.
I don't know if you can pass a culture to the OrganizationService, and I think having different connection strings would work if you want to go this route.
However, you can query the CRM to retrieve the localized labels for the option set you want, as described here.
To sum it up, it's using a RetrieveAttributeRequest, passing the entity logical name and field name and looping trough the result to get the labels.
var request = new RetrieveAttributeRequest
{
EntityLogicalName = "incident",
LogicalName = "casetypecode"
};
var response = organizationService.Execute(request) as RetrieveAttributeResponse;
var optionSetAttributeMetadata = response.AttributeMetadata as EnumAttributeMetadata;
foreach (var option in optionSetAttributeMetadata.OptionSet.Options)
{
Console.WriteLine($"Localized labels for option {option.Value}:");
foreach (var locLabel in option.Label.LocalizedLabels)
{
Console.WriteLine($"Language {locLabel.LanguageCode}: {locLabel.Label}");
}
Console.WriteLine($"Localized description for option {option.Value}:");
foreach (var locLabel in option.Description.LocalizedLabels)
{
Console.WriteLine($"Language {locLabel.LanguageCode}: {locLabel.Label}");
}
}
The code in the link also add caching of already retrieved values, so that you only query the CRM once per option set.

How to safely treat data from JSON when the expected type may differ?

As of iOS 5 and OSX 10.7 and higher it is really easy to parse JSON with NSJSONSerialization, which will return either an NSDictionary or NSArray (or mutable variants, if specified) when parsing JSON. Values are parsed as common Cocoa types such as NSString and NSNumber however I would be interested to know how careful I need to be when taking the data from the NSDictionary or NSArray and parsing it into data objects in my app. My key concerns are whether the key's value a) is not nil and b) isn't of an unexpected type.
For example, assume I had the following JSON object:
{
"version":1,
"title":"Some interesting title",
"info":"Some detail here"
}
Currently, this would be parsed as an NSDictionary:
#{
#"version": #1,
#"title":#"Some interesting title",
#"info": #"Some detail here"
}
My problem is how careful I should be when checking the data types of what I'm getting back. In theory, if I'm using a good API I should always get a numeric value for the version key, but what if for some reason it is changed server side to the following:
{ "version:"1", ... }
Or even worse:
{ "version:"one", ... }
If I attempt the following code, I will get hit an exception and my app would crash:
NSNumber * myNumber = dictionary[#"version"];
if ([myNumber isEqualToNumber:#1])
{
...
}
The code wouldn't execute because a) dictionary[#"version"] would be an NSString and b) isEqualToNumber: is only available on NSNumber (unrecognized selector exception, app would crash).
Equally, problems could arise if the JSON for "info" was changed to the following:
{
"info":{
"code":200,
"message":"Some detail here"
}
}
If my app expects an NSString for the key info it will again crash, because an NSDictionary will have been found instead.
On the large part, most JSON from an API or file should be sound and supported by the current version of the app and one would hope that all JSON is versioned and correctly encoded server side. In some cases, if the JSON has been corrupted or modified, the app could crash, which I want to avoid.
Potential solutions:
Check every single key/value pair for isKindOfClass: or respondsToSelector: and only continue if true
Check the key exists and produce an error if nil
Wrap up everything in a try/catch block, however I would rather what can be used is used and an error is produced if something is wrong with the data. This could end up with a lot of #try/#catch statements inside one another
Each of these solutions is rather bulky and adds a lot to my code which I would prefer to avoid, if possible (and when working with 'good' JSON it is perfectly possible). If there is an alternative solution that will handle the process of parsing JSON, checking keys' type and values before putting it in a custom object I would love to know.
You should generally be running against a stable API. The kind of changes you're worried about should be accompanied by a version number change in any reasonable system which would insulate your app from the change until an appropriate upgrade time. So, you should generally know the data type to expect.
In some cases the API will specify that a dictionary or an array may be received depending on the multiplicity, something like that. In this case you should check the class and act accordingly.
You should definitely check for nil and NSNull and handle those gracefully.
Corrupted JSON should be handled by the parser and an appropriate error returned to you.
Also, you could use a framework like RestKit to do the mapping to your custom objects for you. It does a lot of data type checking as standard and removes basically all of your mapping code into a simple configuration. It also handles all of the network comms (via AFNetworking).
You need to make sure your code is safe against attacks from hackers. When you request JSON from a server, you must expect that the data doesn't come from your server but from somewhere else, and that someone else might have designed the data returned to cause maximum damage. Now just crashing if you receive a string instead of a number is quite secure.
You must expect that your request to the server is instead fulfilled by some brain damaged hardware that tries to be "helpful" for example when an internet connection fails. Instead of JSON you might receive a "helpful" website that is supposed to tell a user how to reset their router. A user trying to use someone's free WiFi may have connections return weird result. That's usually no problem with JSON because the parsing will fail (so failed parsing is something you should expect and handle), more of a problem if you expect html.
You must expect that a public API that you are using has bugs or unexpected behaviour and you should behave well when that happens. Add debugging code that will at least log anything unexpected while you are developing. Write your code so that it works with any behaviour that the API shows.
If you are using your own API, you should also log anything unexpected, and then tell the server people if they do anything they shouldn't.

What is available for limiting the use of extend when using Breezejs, such users cant get access to sensitive data

Basically this comes up as one of the related posts:
Isn't it dangerous to have query information in javascript using breezejs?
It was someone what my first question was about, but accepting the asnwers there, i really would appreciate if someone had examples or tutorials on how to limit the scope of whats visible to the client.
I started out with the Knockout/Breeze template and changed it for what i am doing. Sitting with a almost finished project with one concern. Security.
I have authentication fixed and is working on authorization and trying to figure out how make sure people cant get something that was not intended for them to see.
I got the first layer fixed on the root model that a member can only see stuff he created or that is public. But a user may hax together a query using extend to fetch Object.Member.Identities. Meaning he get all the identities for public objects.
Are there any tutorials out there that could help me out limiting what the user may query.?
Should i wrap the returned objects with a ObjectDto and when creating that i can verify that it do not include sensitive information?
Its nice that its up to me how i do it, but some tutorials would be nice with some pointers.
Code
controller
public IQueryable<Project> Projects()
{
//var q = Request.GetQueryNameValuePairs().FirstOrDefault(k=>k.Key.ToLower()=="$expand").Value;
// if (!ClaimsAuthorization.CheckAccess("Projects", q))
// throw new WebException("HET");// UnauthorizedAccessException("You requested something you do not have permission too");// HttpResponseException(HttpStatusCode.MethodNotAllowed);
return _repository.Projects;
}
_repository
public DbQuery<Project> Projects
{
get
{
var memberid = User.FindFirst("MemberId");
if (memberid == null)
return (DbQuery<Project>)(Context.Projects.Where(p=>p.IsPublic));
var id = int.Parse(memberid.Value);
return ((DbQuery<Project>)Context.Projects.Where(p => p.CreatedByMemberId == id || p.IsPublic));
}
}
Look at applying the Web API's [Queryable(AllowedQueryOptions=...)] attribute to the method or doing some equivalent restrictive operation. If you do this a lot, you can subclass QueryableAttribute to suit your needs. See the Web API documentation covering these scenarios.
It's pretty easy to close down the options available on one or all of your controller's query methods.
Remember also that you have access to the request query string from inside your action method. You can check quickly for "$expand" and "$select" and throw your own exception. It's not that much more difficult to block an expand for known navigation paths (you can create white and black lists). Finally, as a last line of defense, you can filter for types, properties, and values with a Web API action filter or by customizing the JSON formatter.
The larger question of using authorization in data hiding/filtering is something we'll be talking about soon. The short of it is: "Where you're really worried, use DTOs".

How to add / create Foul or bad language keyword filter in SharePoint Lists, Documents?

I am building an Internal social networking website on SharePoint. Since its a networking intranet, I want it to be Open and non moderated. However, I also dont want people to use abusive / Foul or bad language words in the portal.
I tried Googling and wasnt really sucessfull in finding a solution.
Microsoft Forefront will do that for me, but it only does for Documents. But I also want to do that on Lists since Discussion forum on the SharePoint is in a list format.
You may create site solution/list definition for your site using Visual studio Sharepoint Site Solution Genarator. Create a custom list and name it as you wish. I would name it "AbusiveWordList" in the following code example.
After creating site solution/list definition, Add below code in Item Adding function, which will iterate through all column in the list and will check from the custom list that is created named "AbusiveWordList". This list contains abusive words.
The chkbody function which will reference list item from custom list named "AbusiveWordList" and check if the bodytext contains item from AbusiveWordList.If yes, then it will throw an error.
*base.ItemAdding(properties);
foreach (DictionaryEntry
dictionaryEntry in
properties.AfterProperties) { string
bodytext = "";
bodytext = bodytext +
dictionaryEntry.Value;
finalwordcount = finalwordcount +
chkbody(bodytext, properties); }
if (finalwordcount > 0) {
properties.ErrorMessage = "Abusive /
Foul / Illicit information
found.Kindly refer to the terms and
conditions.";
properties.Cancel = true;
}
You will probably need to override any controls that display text to avoid this issue. As this would be a lot of work, perhaps an HTTP Module would be a better solution.
I've worked on a module that used regular expressions to make SharePoint's output XHTML compliant. Similarly, you could use regular expressions to strip out offensive words when a page is rendered. It wouldn't stop people typing them but as no-one would be able to see them this wouldn't matter. You could use a basic SharePoint custom list to store the offensive words you don't want displayed.

Resources