NSLocalizedString should be used directly for exporting XLIFF? - xcode

I used to use NSLocalizedString by custom function.
For example, to access Profile.strings, I define this function:
func LocalizedProfile(key: String, comment: String?) {
NSLocalizedString(key, tableName: "Profile", comment: comment ?? "")
}
And, called like this:
let localized = LocalizedProfile("Submit", comment: "For registration")
This method works fine except for exporting XLIFF.
On the Xcode 6.3.2, executting Export for localizationthrows error:
To get error information, I executed via command line:
xcodebuild -exportLocalizations -localizationPath ./xliff -project MyApp.xcodeproj -exportLanguage ja
And, I got this error:
Bad entry in file /Users/mono/Documents/Git/MyApp/Localization.swift (line = 29): Argument is not a literal string.
Defining custom localization method is very useful for me, but I also want to use exporting XLIFF feature.
Are there any methods to resolve this demands?

Export For Localization and xcodebuild -exportLocalizations both generate strings files by looking for invocations of NSLocalizedString(_:tableName:bundle:value:comment:) in code and uses the static values passed into the parameters to create the appropriate strings files.
This means that the only values you can pass into key, comment, value, and tableName are string literals.
Since you're using a wrapper function around NSLocalizedString(_:comment:) to localize your strings, the only time Xcode sees you calling NSLocalizedString(_:comment:) is in that one wrapper function with non-string-literal values, which is invalid.
What you really want to do instead is call NSLocalizedString(_:tableName:comment:) directly.
Alternatively, you can call Bundle.localizedString(forKey:value:table:) in your wrapper function, but then you have to manually create your own strings files for those key-value pairs.
/// - parameter comment: This value is ignored, but should be provided for
/// context at the call site about the requested localized string.
func LocalizedProfile(key: String, comment: String?) -> String {
return Bundle.main.localizedString(forKey: key, value: nil, table: "Profile")
}

Related

Powerautomate Parsing JSON Array

I've seen the JSON array questions here and I'm still a little lost, so could use some extra help.
Here's the setup:
My Flow calls a sproc on my DB and that sproc returns this JSON:
{
"ResultSets": {
"Table1": [
{
"OrderID": 9518338,
"BasketID": 9518338,
"RefID": 65178176,
"SiteConfigID": 237
}
]
},
"OutputParameters": {}
}
Then I use a PARSE JSON action to get what looks like the same result, but now I'm told it's parsed and I can call variables.
Issue is when I try to call just, say, SiteConfigID, I get "The output you selected is inside a collection and needs to be looped over to be accessed. This action cannot be inside a foreach."
After some research, I know what's going on here. Table1 is an Array, and I need to tell PowerAutomate to just grab the first record of that array so it knows it's working with just a record instead of a full array. Fair enough. So I spin up a "Return Values to Virtual Power Agents" action just to see my output. I know I'm supposed to use a 'first' expression or a 'get [0] from array expression here, but I can't seem to make them work. Below are what I've tried and the errors I get:
Tried:
first(body('Parse-Sproc')?['Table1/SiteConfigID'])
Got: InvalidTemplate. Unable to process template language expressions in action 'Return_value(s)_to_Power_Virtual_Agents' inputs at line '0' and column '0': 'The template language function 'first' expects its parameter be an array or a string. The provided value is of type 'Null'. Please see https://aka.ms/logicexpressions#first for usage details.'.
Also Tried:
body('Parse-Sproc')?['Table1/SiteconfigID']
which just returns a null valued variable
Finally I tried
outputs('Parse-Sproc')?['Table1']?['value'][0]?['SiteConfigID']
Which STILL gives me a null-valued variable. It's the worst.
In that last expression, I also switched the variable type in the return to pva action to a string instead of a number, no dice.
Also, changed 'outputs' in that expression for 'body' .. also no dice
Here is a screenie of the setup:
To be clear: the end result i'm looking for is for the system to just return "SiteConfigID" as a string or an int so that I can pipe that into a virtual agent.
I believe this is what you need as an expression ...
body('Parse-Sproc')?['ResultSets']['Table1'][0]?['SiteConfigID']
You can see I'm just traversing down to the object and through the array to get the value.
Naturally, I don't have your exact flow but if I use your JSON and load it up into Parse JSON step to get the schema, I am able to get the result. I do get a different schema to you though so will be interesting to see if it directly translates.

phoenix translate msg without put_locale

I have an array of users, each with its own locale.
I need to get a translation of the message into the language of each user.
...
Enum.map(user.tokens, fn(t) -> t.token end)
|> Sender.send(translated_msg(user.locale, msg))
...
defp translated_msg(locale, msg) do
message = Gettext.with_locale MyApp.Gettext, locale, fn ->
MyApp.Gettext.gettext(msg.body, msg.bindings)
end
message
end
where
msg = %{body: "%{login} added a new operation", bindings: %{login: current_user.login}}
But such code is not compiled
== Compilation error on file web/helpers/sender_helper.ex ==
** (ArgumentError) *gettext macros expect translation keys (msgid and msgid_plural) and
domains to expand to strings at compile-time, but the given msgid
doesn't.
Dynamic translations should be avoided as they limit gettext's
ability to extract translations from your source code. If you are
sure you need dynamic lookup, you can use the functions in the Gettext
module:
string = "hello world"
Gettext.gettext(MyApp.Gettext, string)
(gettext) lib/gettext/compiler.ex:196: anonymous fn/2 in Gettext.Compiler.expand_to_binary/4
expanding macro: MyApp.Gettext.dgettext_noop/2
web/helpers/push_helper.ex:23: MyApp.SenderHelper.translated_msg/2
expanding macro: MyApp.Gettext.dgettext/3
web/helpers/push_helper.ex:23: MyApp.SenderHelper.translated_msg/2
expanding macro: MyApp.Gettext.gettext/1
web/helpers/push_helper.ex:23: MyApp.SenderHelper.translated_msg/2
(elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1
How can I manually translate a message into another language?
Just like the error message says, if the string to translate is dynamic, you need to use Gettext.gettext/{2,3} passing in your app's Gettext module as the first argument. Since you're passing bindings as well, you need to use Gettext.gettext/3:
Gettext.gettext(MyApp.Gettext, msg.body, msg.bindings)

How to get XPages and JSON to not put variable names in Uppercase

I'm trying to do the following update using XPages Extension Library.
#{javascript:var mydata = {
product: getComponent("inputProduct").getValue()
};
var params = [1, 2];,
#JdbcUpdate("mssql","table_name",mydata,"order_no=? AND order_line_no=?",params)};
I get the error:
Error while executing JavaScript action expression
Script interpreter error, line=6, col=1: Error while executing function '#JdbcUpdate'
Invalid column name 'PRODUCT'.
The problem is that XPages when it converts the JSON it puts product to PRODUCT.
Can you set the extension library to respect the case of the JSON and not convert to Uppercase? Or can anyone point to where this setting could be set if not the extension library?
Thanks
The problem is com.ibm.xsp.extlib.util.JdbcUtil.appendColumnName()
public static void appendColumnName(StringBuilder b, String colName) {
colName = colName.toUpperCase();
b.append(colName);
}
This just needs changing to not upper case the variable.
There may be other methods that need changing if other variables are getting upper cased.

Freemarker - replace & with &

If i have the & symbol in some field (from a db, cannot be changed), and i want to display this via freemarker... but have the display (from freemarker) read &, what is the way to do so?
To reiterate, I cannot change the value before hand (or at least, I don't want to), i'd like freemarker to "unmark" &.
To double re-iterate, this is a value that is being placed with a lot of other xml. The value itself is displayed on its own, surrouded by tags... so something like
<someTag>${wheeeMyValueWithAnAmpersand}<someTag>
As a result, i don't want all ampersands escaped, or the xml will look funny... just that one in the interpolation.
Oh goodness.
I see the problem: the code was written like this:
<#escape x as x?xml>
<#import "small.ftl" as my>
<#my.macro1/>
</#escape>
and at which i'd assumed that the excape would excape all the calls within it - it is certainly what the documentation sort of implies
http://freemarker.org/docs/ref_directive_escape.html
<#assign x = "<test>"> m1>
m1: ${x}
</#macro>
<#escape x as x?html>
<#macro m2>m2: ${x}</#macro>
${x}
<#m1/>
</#escape>
${x}
<#m2/>
the output will be:
<test>
m1: <test>
<test>
m2: <test>
However it appears that when you import the file, then this isn't the case, and the escape... escapes!
SOLUTION:
http://watchitlater.com/blog/2011/10/default-html-escape-using-freemarker/
the above link details how to solve the problem. In effect, it comes down to loading a different FreemakerLoader, one that wraps all templates with an escape tag.
class SomeCoolClass implements TemplateLoader {
//other functions here
#Override
public Reader getReader(Object templateSource, String encoding) throws IOException {
Reader reader = delegate.getReader(templateSource, encoding);
try {
String templateText = IOUtils.toString(reader);
return new StringReader(ESCAPE_PREFIX + templateText + ESCAPE_SUFFIX);
} finally {
IOUtils.closeQuietly(reader);
}
}
which is a snippet from the link above. You create the class with the existing templateLoader, and just defer all the required methods to that.
Starting from FreeMarker 2.3.24 no TemplateLoader "hack" is needed anymore. There's a setting called output_format, which specifies if and what escaping is needed. This can be configured both globally, and/or per-template-name-pattern utilizing the template_configurations setting. The recommend way of doing this is even simpler (from the manual):
[...] if the
recognize_standard_file_extensions setting is true (which is the
default with the incompatible_improvements setting set to 2.3.24 or
higher), templates whose source name ends with ".ftlh" gets "HTML"
output format, and those with ".ftlx" get "XML" output format

How do I use a guid in a mongodb shell query

When using the MongoDB shell, how do I use a guid datatype (which I have used as the _id in my collection).
The following format doesn't work:
>db.person.find({"_id","E3E45566-AFE4-A564-7876-AEFF6745FF"});
Thanks.
You can use easily:
.find({ "_id" : CSUUID("E3E45566-AFE4-A564-7876-AEFF6745FF")})
You have to compare the _id value against an instance of BinData (not against a string). Unfortunately the BinData constructor takes a Base64 string instead of a hex string.
Your GUID value is missing two hex digits at the end, so for the purposes of this example I will assume they are "00". The following values are equivalent:
hex: "E3E45566-AFE4-A564-7876-AEFF6745FF00" (ignoring dashes)
base64: "ZlXk4+SvZKV4dq7/Z0X/AA=="
So your query should be:
>db.person.find({_id : new BinData(3, "ZlXk4+SvZKV4dq7/Z0X/AA==")})
I am assuming that the binary subtype was correctly set to 3. If not, what driver was used to create the data?
You could use the following js function in front of your query like so:
function LUUID(uuid) {
var hex = uuid.replace(/[{}-]/g, ""); // removes extra characters
return new UUID(hex); //creates new UUID
}
db.person.find({"_id" : LUUID("E3E45566-AFE4-A564-7876-AEFF6745FF"});
You could save the function in .js file and load it or open it before you make your query and if you copy the value from your results you should rename the function with:
LUUID for Legacy UUID
JUUID for Java encoding
NUUID for .net encoding
CSUUID for c# encoding
PYUUID for python encoding
I know it's an old issue, but without any additional needs you can use this one:
find({_id:UUID('af64ab4f-1098-458a-a0a3-f0f6c93530b7')})
You can fix this issue by using split() and join() workaround:
for instance if I use "E3E45566-AFE4-A564-7876-AEFF6745FF" hex value with - inside UUID() function, it does not return BinData in mongo so please try removing all the - before passing to UUID function.
db.person.find({"_id":UUID("E3E45566-AFE4-A564-7876-AEFF6745FF".split("-").join(''))});
Or by defining a variable to do it in multiple line:
var uuid = UUID("E3E45566-AFE4-A564-7876-AEFF6745FF".split("-").join(''))
db.person.find({"_id":uuid});
or by creating a simple function:
function BUUID(uuid){
var str = uuid.split("-").join('');
return new UUID(str);
}
db.person.find({"_id": BUUID("E3E45566-AFE4-A564-7876-AEFF6745FF")}).pretty();

Resources