Strings in init are not localized - swiftui

I do localization of my iOS SwiftUI app and using XCode Product/Export localizations.. function to create xcloc file. Everything works fine but strings in init() are not detected in shown in xcloc. Is there any way how to add them?
Thanks

You should replace all relevant String types that are initialized with static string literals with LocalizedStringKey, mainly in the funcs and init()s – so for example:
struct MyStruct {
var myVar: LocalizedStringKey
init(var: LocalizedStringKey) {
self.myVar = var
}
...
}
Stringtypes in model data have to stay untouched.
If there are missing cases left you can add them manually to your .strings file by
"original text" = "localized text";

Related

Can Apple Watch workout metadata use JSON strings?

I've got a working Apple Watch workout app. My metadata saves and all workout data flows to iPhone. I'm also able retrieve and display the data. But when i try to add arrays converted to ... json strings ... to metadata, the app crashes on save. Every time. I've tried numerous variations, always it's the same. Here's the latest code to crash... and it's perfectly fine.
GOOD CODE that works, but return string...
CRASHES with every HKWorkoutSession save.
func toJSON(array: [[String: Any]]) throws -> String {
let data = try JSONSerialization.data(withJSONObject: array, options: [])
return String(data: data, encoding: .utf8)!
}
NOW ... when my configuration class is converted with strings created using the function below, metadata saves just fine... and i'm back where i started. Wondering how to restore the [[String:Any]] arrays from String.
SAVES on WatchOS 3
This code creates a string from array of dictionaries.
What I'm needing help with is function to restore strings created using this function back into original form of [ [ String : Any ] ]
func joinedRepresentationOfArrayOfArrays(newArray: [[String : Any]]) -> String {
var newString = ""
for dictionary in newArray {
newString = newString.appending("[")
for (key, value) in dictionary {
newString = newString.appending("[\(key) : \(value), ")
}
newString = newString.appending("], ")
}
newString = newString.appending("], ")
return newString
}

Matching parameters of a function with Regex

What I have so far: \w+\(((".+")|(\d+))+\)I'm not sure how to go about matching more than one paramter separated by a comma. How can I capture the parameters (and function names) of the following test cases?
scroll("foo")
scroll("foo",55)
scroll("foo","bar")
scroll("foo","bar",55)
scroll(55)
scroll(55,"foo")
scroll(55, 13,"foo","bar")
For example, in the last one the groups must be scroll, 55, 13, "foo", and "bar".
Edit: Language is AS3
Try this lengthy regex:
(\"?\w+\"?)\((\"?\w+\"?)(?:[,\s]+(\"?\w+\"?))?(?:[,\s]+(\"?\w+\"?))?(?:[,\s]+(\"?\w+\"?))?\)?
The code above is set to capture up to five parameters. You can adjust that by adding/removing this code (?:[,\s]+(\"?\w+\"?))? based on your needs.
Demo: https://regex101.com/r/o1RRSG/1
i hope i'm in right way
you want to split for example
this: scroll ( 55, 13, "foo", "bar" )
to its function name and arguments like
this: scroll ( 55, 13, "foo", "bar" )
a better result of expression:
i just assume additional white spaces for more accuracy
the regex fot would be :
[^\t (,)]
Okay, you may not like it, but it's flawless as long as you have ExternalInterface backed with JS available. And it's funny. (While doing this with reg exps is the opposite of fun.)
The idea is to let JS do its eval. The manual says you have to pass a function name to ExternalInterface.call(), which is not true: pass just any code that evaluates to a function reference. This way you can inject any JS code into the page where your SWF resides (which is why AllowScriptAccess is such a terribly dangerous attribute).
public class Test extends Sprite
{
public function Test()
{
var test = "scroll(55, 13,\"foo\",\"bar\", \"now(), we are \\\"screwed\\\")\")";
trace(test);
var details = parseFunctionCall(test);
trace(details[0]);
for (var i = 1; i<details.length; i++) {
trace("\t"+i+": "+typeof(details[i])+" "+details[i]);
}
}
private function parseFunctionCall(input:String):Array
{
if (ExternalInterface.available) {
var split:RegExp = /^(\w+)\((.+)\)$/;
var info = split.exec(input);
var inject = "(function(){return ["+info[2]+"];})";
var params = ExternalInterface.call(inject);
params.unshift(info[1]);
return params;
}
return null;
}
}
/*
Output:
scroll
1: number 55
2: number 13
3: string foo
4: string bar
5: string now(), we are "screwed")
*/

Scala.js js.Dynamic usage leads to a recursively infinite data structure

I'm trying to use Google Visualizations from Scala.js. I generated the type definitions using TS importer and the relevant portion it generated is:
#js.native
trait ColumnChartOptions extends js.Object {
var aggregationTarget: String = js.native
var animation: TransitionAnimation = js.native
var annotations: ChartAnnotations = js.native
// ... more
}
#js.native
trait TransitionAnimation extends js.Object {
var duration: Double = js.native
var easing: String = js.native
var startup: Boolean = js.native
}
Now, I'm trying to figure out how to actually use this and came up with:
val options = js.Dynamic.literal.asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal.asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
options.animation.duration = 2000
options.title = "Test Chart"
options.width = 400
options.height = 300
This works if I don't set the animation settings, but fails with the chart showing "Maximum call stack size exceeded" if I do.
I debugged, and found the following:
So animation contains a reference to itself, but I don't feel like this should happen based on the code above.
Ideas how to fix it?
Any other suggestions on how to best use the generated types to provide a type-safe way of creating the JavaScript objects which Google Visualizations expects? I tried new ColumnChartOptions {} which looks cleaner than js.Dynamic but that failed with "A Scala.js-defined JS class cannot directly extend a native JS trait."
P.S. I'd like to note that
options.animation = js.Dynamic.literal(
easing = "inAndOut",
startup = true,
duration = 2000
).asInstanceOf[TransitionAnimation]
actually works, but isn't type-safe (a mis-spelling of duration to durration won't be caught).
Your code lacks () when calling literal(), so the fix would be:
val options = js.Dynamic.literal().asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal().asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
In Scala (and therefore in Scala.js), the presence or absence of () is sometimes meaningful. literal is the singleton object literal, whereas literal() calls the method apply() of said object.

How to create list from another typed list with 'List.from'?

Simple dart code:
class User {
String name;
User(this.name);
}
main() {
List<User> users = [new User('Freewind')];
var list = new List.from(users);
print(list.first.name); // ***
}
Notice the line ends with '// *'.
My IDEA editor doesn't recognize list.first as a User, since it can't do the autocompletion when I typed '.name'.
So I have to declare the type:
List<User> list = new List.from(users);
It works but I want to know if there is any other way to let compiler know list has type List<User>?
I tried:
var list = new List<User>.from(users);
Which has wrong syntax.
This one works for me in DartEditor (no error/warning/hint) and of course executes successfully
var list = new List<User>.from(users);

AS3/Regular Expressions - Replacing segments of a string

I have absolutely no knowledge in Regex whatsoever. Basically what I'm trying to do is have an error class that I can use to call errors (obviously) which looks like this:
package avian.framework.errors
{
public class AvError extends Object
{
// errors
public static const LAYER_WARNING:String = "Warning: {0} is not a valid layer - the default layer _fallback_ has been used as the container for {1}.";
/**
* Constructor
* Places a warning or error into the output console to assist with misuse of the framework
* #param err The error to display
* #param params A list of Objects to use throughout the error message
*/
public function AvError(err:String, ...params)
{
trace(err);
}
}
}
What I want to be able to do is use the LAYER_WARNING like this:
new AvError(AvError.LAYER_WARNING, targetLayer, this);
And have the output be something along the lines of:
Warning: randomLayer is not a valid layer - the default layer _fallback_ has been used as the container for [object AvChild].
The idea is to replace {0} with the first parameter parsed in ...params, {1} with the second, etc.
I've done a bit of research and I think I've worked out that I need to search using this pattern:
var pattern:RegExp = /{\d}/;
You can use StringUtil
var original:String = "Here is my {0} and my {1}!";
var myStr:String = StringUtil.substitute(original, ['first', 'second']);
Using the g flag in RegExp you can create an array containing all of your {x} matches, then loop through this array and replace each of the matches with the appropriate parameter.
Code:
var mystring:String = "{0} went to {1} on {2}";
function replace(str:String, ...params):String
{
var pattern:RegExp = /{\d}/g;
var ar:Array = str.match(pattern);
var i:uint = 0;
for(i; i<ar.length; i++)
{
str = str.split(ar[i]).join(params[i]);
}
return str;
}
trace(replace(mystring, "marty", "work", "friday")); // marty went to work on friday
i'm assuming you want to have several static constants with varying replacement instances ({0}, {1}, {2}, etc.) in each string constant.
something like this should work - sorry, it's untested:
public function AvError(err:String, ...params)
{
var replacementArray:Array = err.match(new RegExp("{\\d}", "g"));
for (var i:int = 0, i < replacementArray.length, i++)
err = err.replace(new RegExp(replacementArray[i], "g"), params[i]);
trace(err);
}
if you do have several static constants with varying replacement instances, you'll want to check for an appropriate matching amount of …params that are passed.