Swift - Localizable file working properly in all except one iPad device - ios

I am currently working on an Xcode project that has several different targets, each one with their own strings defined for specific parts of the app. That is why we are using different string files, which we call depending on the target we are running.
I came across a strange problem which I still could not find a way to reproduce. One of the devices of a client is showing the name of the key instead of showing the string defined for that target or the default string in the file "default.string". The problem is that all other test devices (simulator and physical devices) we used show the strings correctly. The device that is not showing strings properly (and just showing the key) is an iPad 7th Generation, with iPadOS 14.
I am using the following code to show the string on the view (note that I am using "section2HomeTitle" as an example here):
FactoryView.sectionHeaderView(with: Strings.localizedString(forKey: Strings.LocalizedStringKey.section2HomeTitle), icon: Constants.Config.useIconSectionsHomeTitle ? #imageLiteral(resourceName: "imbatibles"): nil )
The key section2HomeTitle is defined in a file for Constants the following way:
struct Strings {
struct LocalizedStringKey {
static let section2HomeTitle = "section2HomeTitle"
}}
Also in the Constants file, I have the following function defined, which looks for the definition of key "section2HomeTitle" in the localized files:
static func localizedString(forKey key: String) -> String {
var result = Bundle.main.localizedString(forKey: key, value: nil, table: Constants.Config.store)
if result == key {
result = Bundle.main.localizedString(forKey: key, value: nil, table: "default")
}
return result
}
That function looks for the current target's definition for that particular key using Constants.Config.store. If it does not find the key in that target's file, it will look for it in the default file.
In this case I am dealing with Target store "xyz", and therefore I define its keys in file xyz.string which has Localization language set to Spanish and Target Membership set to "xyz" target. The key is defined in that file with the following string:
"section2HomeTitle" = "REBAJAS";
In case the file is not found, I have the "default" file defined as default.string which has Localization language set to Spanish and Target Membershipt set to "xyz" target and all other targets in the project. The key definition here is:
"section2HomeTitle" = "Ofertas";
As I mentioned before, the output shows up as "REBAJAS" in all devices we tested for that target, except in that one iPad 7th Gen from the client, where it shows:section2HomeTitle
My questions are:
Why is this key showing up correctly in all devices we test it, except on the client's iPad 7th Gen
What can I do to correct this issue?
Thank you.

Related

How to programmatically add Language translation key value pair to .resx resource file in Blazor server?

I want to add key value pair to GlobalResources.en-US.resx file. This is the file used by localization in my Blazor Server app.
public void Add()
{
if(!string.IsNullOrEmpty(Key) && !string.IsNullOrEmpty(Value))
{
IResourceWriter resWriter = new ResourceWriter(
#".\my_path\Resources\GlobalResources.en-US.resx");
resWriter.AddResource(Key, Value);
resWriter.Close();
}
}
I have replaced the correct path with placeholder my_path to make it shorter here.
But after executing this method, I can't view GlobalResources.en-US.resxfile in Visual studio.It says ResX file Data at the root level is invalid. Line 1, position 1. cannot be parsed. So I can't get to know whether that key, value is correctly added or not. Also localization service do not pick that value.
How can I programmatically add Language translation key value pair to this resource file in Blazor server?

iOS project - Strange characters in localized strings

The localized strings are loaded with strange characters in my iOS project.
Like instead of "Home" it gets "H̀o̥m̧ë"
I set up 3 .strings files to store the strings used in the project and used swiftgen to generate the enum for using them. (I don't know if this info is relevant, just wanted to give the most comprehensive picture.)
I have my strings like:
"backHomeNavButton" = "Home";
The code that was generated by swiftgen is:
{
…
private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
let format = BundleToken.bundle.localizedString(forKey: key, value: nil, table: table)
return String(format: format, locale: Locale.current, arguments: args)
}
…
}
private final class BundleToken {
static let bundle: Bundle = {
Bundle(for: BundleToken.self)
}()
}
The string is already the above mentioned result at let format inside tr(_:_:_:)
Did anyone experienced something similar?
I already tried adding a new .strings file, the results is the same.
I checked it in another project without swiftgen, it worked there. Then I compared those Build Settings that contained Localiz and the projects had the same settings.
I am using Xcode 12.5 at the moment, but when I opened the project in Xcode 12.4 I got the same results.
Thanks for your help in advance.
I figured it out since, so I leave the solution here if anyone gets in the same situation.
You can change the App Language in the Build Scheme. and if you set it to Accented Pseudolanguage, then it will produce these strange characters.

Localizable strings shows key instead of value every other time

I have a weird inconsistency with my localizable strings where sometimes the value is shown and sometimes thee key is shown. It's about every other time I restart the app. I use a lot of localizable strings in the project and they all work fine except for the ones I use in conjunction with this enum, which of course makes me think there is something wrong with it:
enum ParameterDescription {
case parameterDescription(id: Int)
var description: String {
switch self {
case .parameterDescription(let id):
return "parameterDescription_\(id)"
}
}
}
This returns the string I expect, like parameterDescription_0 or parameterDescription_3. And then I hook on localized:
print(ParameterDescription.parameterDescription(id: 0).description.localized())
extension String {
func localized() -> String {
return NSLocalizedString(self, comment: "")
}
}
And sometimes I get the correct associated value, but if I build and run the code again without changing anything, I (might) get the key printed as a string instead, which I guess means that Xcode couldn't find the string.
Is there something wrong with the enum or some reason it can't be used like this? Or is it something else? I have checked through the project folders so that there aren't any conflicting files, and as I previously said, I only experience this problem using this enum and/or this key. And there are thousands of localized strings in the project.
I have checked similar threads, but there doesn't seem to be any answer that is relevant for this.

How to find source file and line number from os_log()

The Logging Apple reference for the new logging system in iOS 10 and macOS Sierra explicitly say not to include line number and source file info, because it is automatically captured.
Don’t include symbolication information or source file line numbers in messages. The system automatically captures this information.
But I have yet to be able to find any way of viewing these supposedly captured values. In the Console app I can see subsystem, category, process ID, etc, but nothing about file and line.
And the command line tool similarly appears to lack any options for displaying this information (unless I'm missing something).
Anyone figured it out yet?
I don't think it's available in Swift yet, although you can see file and line number in C / C++ in Terminal. See Apple forum here.
I tried something similar to what's inside the forum by creating a simple command-line tool Xcode project:
import Foundation
import os.log
os_log("rrrr")
and type the following in Terminal: log stream --source --predicate 'eventMessage contains "rrrr"', and I got this:
Timestamp Thread Type Activity PID
2017-02-18 17:58:46.012381+0700 0x5067d Default 0x0 5637 <testLogSwift`_swift_os_log> rrrr
in contrast to what I got in C/C++ version, which shows the file and line number:
Timestamp Thread Type Activity PID
2017-02-18 17:55:05.056103+0700 0x4aa01 Default 0x0 5218 <testLogging`main (main.cpp:13)> qqq
Till apple fixes this issue,
I've created a simple extension
import os
extension Logger {
init(subsystem: String = Bundle.main.bundleIdentifier ?? "", file: String = #file, function: String = #function, line: Int = #line, context: String) {
let category = "\(file):\(line):\(function), \(context)"
self.init(subsystem: subsystem, category: category )
}
}
Usages:
Logger(context: "LoginFLow").debug("Hello World")
We can even remove param name to make it more cleaner:
import os
extension Logger {
init(subsystem: String = Bundle.main.bundleIdentifier ?? "", file: String = #file, function: String = #function, line: Int = #line, _ context: String) {
let category = "\(file):\(line):\(function), \(context)"
self.init(subsystem: subsystem, category: category )
}
}
Usages:
Logger("LoginFLow").debug("Hello World")
Note: If you wish to use the original Logger, just remove the context param and it will use its original init provided by apple.
Logger().debug("Hello World")

Enable iCloud on a Xcode project via script

i am trying to setup a build server for a continuous building on a iOS project.
Since that i need to recreate the Xcode project very often (it is a build from unity), the iCloud will be reset to OFF.
I can copy the entitlement file (with the iCloud key) via script but i still need to click on the actual checkbox to turn iCloud ON.
I managed to change the XC project manually but it is not very safe, due to possible changes on XC project structure.
Do you know a better way to do this?
Cheers!
Apparently the TO solved the problem but since there seem to be more people interested in this, here a possible solution.
You can make a script to edit the project.pbxproj which is inside your xcodeproj file (can be viewed e.g. with "show package contents" options in finder).
In this file there's a section for project settings called PBXProject section. There you can add the capabilities for the targets. You probably need to write custom parsing logic, since this file is written in XCode config format, no anything popular like XML or JSON.
The part which you want to update looks like this:
/* Begin PBXProject section */
EB1DDE9C1A3334EC00D778DE /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0610;
/* ...more settings */
TargetAttributes = {
EB1DDEA31A3334EC00D778DE = {/* this is one target */
CreatedOnToolsVersion = 6.1.1;
DevelopmentTeam = 37QAPDY2PR;
/* ...more settings */
};
EB9F6CE11A8812550038355B = {/* another possible target */
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 37QAPDY2PR;
/* ...more settings */
};
};
};
/* ...more settings */
};
/* End PBXProject section */
You want to add the iCloud capabilities to the targets. This looks like this:
SystemCapabilities = {
com.apple.iCloud = {
enabled = 1;
};
};
So let's say you want to add iCloud capability to the target EB1DDEA31A3334EC00D778DE, then the TargetAttributes entries will look like this:
TargetAttributes = {
EB1DDEA31A3334EC00D778DE = {/* this is one target */
CreatedOnToolsVersion = 6.1.1;
DevelopmentTeam = 37QAPDY2PR;
SystemCapabilities = {
com.apple.iCloud = {
enabled = 1;
};
};
};
EB9F6CE11A8812550038355B = {/* another possible target */
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 37QAPDY2PR;
/* ...more settings */
};
};
Now there are some things you need to determine in order to do this:
1. Identify the section
I'd make the script look for the string "Begin PBXProject section" and then for "TargetAttributes" both of which are unique in the file. Theoretically "TargetAttributes" should be enough but better to be safe... and remember to add proper logging to the script and verify the results, because these strings could easily change in future XCode versions (I have seen them unchanged, though, a while already).
2. Identify the target
There are multiple parts in this file where you can see the id of the target associated with the name. I would just look this up myself and hardcode it in the script, as this id will not change unless you re-create the target. If you really need it you can also automate this... by looking for your target's name and the format where it appears associated with the id. There should be also other config files where this association appears (in this file the name just appears as a comment).
3. Handle situation that there is already a SystemCapabilities entry for the target, and also that there is already iCloud entry.
If your target has other capabilities this entry may already exist. Also if you already have iCloud enabled or if you had once iCloud enabled and disabled it, the entry will also exist (with a 0 value). This has to be handled in the script (latest should not be a problem if the project file is new though).
Besides of that, you also probably have to add a reference to the entitlements file. You have to add this to the build configurations of the respective targets. For this:
4. Find the build configuration id(s)
Your target has probably multiple build configurations, e.g. debug and release. You have to find the id of the build configuration(s) for which you want to add a reference to the entitlements file. To do this there's a section called XCConfigurationList (look for /* Begin XCConfigurationList section */). There look for the target id we got in 1., Then find the configuration id(s) for the configurations you need.
5. Look for build configuration id in XCBuildConfiguration section
Go to /* Begin XCBuildConfiguration section */ and look for id(s) found in 5., then add path to entitlements to it's buildSettings. E.g:
E.g. you have sth like
EB9F6CF33A861055BB38355B /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B82B36921BDRI3622B0EC99 /* Pods-mytargetname.debug.xcconfig */;
buildSettings = {
/* build settings... */
CODE_SIGN_ENTITLEMENTS = mytargetname/myentitlements.entitlements; /* <-- add this */
};
name = Debug;
};
Note that XCode should "know" the entitlements file (just like the rest of your project files).

Resources