Is it possible to replace {} with a backspace for localizations - json

We are using flutter easy localizations and we have texts that use arguments. So for example we have a string in our localizations doc like below,
{
"someAppText":"This is {} app text {}."
}
But sometimes the argument will be empty. Which will result in the following text
This is[SPACE][SPACE]app text[SPACE].
Where the spaces are still there. Is it possible to do a backspace whenever we have no arguments?

Firstly, what about using plural? Sounds like you want to have a different text for different kind of data. I do not come up with other examples when an arg will be empty, so if it is not your case could you please give a concrete example?
Secondly, you can do simple string manipulation as follows (pseudocode). The code only demonstrates the simplest case (to make it brief), but it is trivial to extend to the full case.
String myTranslate(String formatString, List<String> args) {
const EMPTY_MARKER = 'EMPTY_MARKER';
final transformedArgs = args.map((arg) => arg.isEmpty ? EMPTY_MARKER : arg).toList();
final rawString = formatString.tr(transformedArgs);
return rawString.replaceAll(' $EMPTY_MARKER', '');
}
Then in your example, it will output: This is[SPACE]app text.

we can not add any methods inside a JSON file, and only have to use it's simple map<String, String> data
so
a work around solution would use special strings inside the JSON to be able to detect and process them in run time
let's say JSON would have this
{
"someAppText": "This is #VAR01 app text #VAR02."
}
then let us create another class that has methods to handle these special words, they should detect them, and replace them with other dynamic inputs
so
class JSONWorkAround {
/// A - need to define the string pattern we are using in the string which I assumed to look like '#VAR00'
/// let's call them jsonVariables
/// NOTE : if you would like to name them #VAR000 ,, then regExp would be r'#VAR...'
static RegExp regExp = RegExp(r'#VAR..');
/// B - let's make a tracker for any word that matches this regExp in any input string
static List<String> _searchJSONVariablesByRegExp({#required String text, #required RegExp regExp}){
List<String> _strings;
/// always check if not null before we do stuff to avoid errors and save performance
if (text != null){
_strings = regExp.allMatches(text).map((m) => m.group(0)).toList();
}
return _strings;
}
/// C - let's make the tracker specifically for those JSONVariables from a string received from the JSON doc "let's call it rawString"
static List<String> _searchJSONVariablesFromRawString({#required String rawString}){
final List<String> _jsonVariables = _searchJSONVariablesByRegExp(text: rawString, regExp: regExp);
return _jsonVariables;
}
/// E - let's see what to do with the search result
static List<SpecialWord> _processJSONVariables(List<String> jsonVariables){
List<SpecialWord> _outputSpecialWords = <SpecialWord>[];
/// so w notice we will need to process each one alone,, so we loop them out
if(jsonVariables != null && jsonVariables.isNotEmpty){
jsonVariables.forEach((jsonVariable) {
/// we should receive a substitute string instead of that #VAR00 special string,, so ..
/// actually we need to receive a string that is accompanied with its cipher special thing to be able to go back to the sentence and change it,,, like using this special #VAR00 thing as ID
/// and I don't like map<String, dynamic> but I would rather create a model class ,, will be written down there at the end of this class
final SpecialWord _substitute = _processSingleJSONVariable(jsonVariable: jsonVariable);
/// then we add them to the output List
if (_substitute != null){
_outputSpecialWords.add(_substitute);
}
});
}
return _outputSpecialWords;
}
/// D - need to receive both the substitute and its (JSONSpecialVariable / ID) to be able to search for it and process it in the original string
static SpecialWord _processSingleJSONVariable({#required String jsonVariable}){
final SpecialWord _substitute = SpecialWord.getSpecialWordFromAllSpecialWordsByID(jsonVariable);
return _substitute;
}
/// F - finally after receiving the substitutes inside a list<SpecialWord>,, we get get back the original String with the substitutes
static String processJSONStringThatContainsThoseSpecialVariables(String rawString){
/// this has to initialize with the initial raw string value to be processed
String _processedString = rawString;
final List<String> _jsonVariables = _searchJSONVariablesFromRawString(rawString: rawString);
if (_jsonVariables != null && _jsonVariables.isNotEmpty){
final List<SpecialWord> _specialWords = _processJSONVariables(_jsonVariables);
/// then we need to change each jsonVariable with its substitute
_specialWords.forEach((specialWord) {
_processedString = _replaceSubStringWith(
subStringToReplace: specialWord.id,
replacement: specialWord.substitute,
input: _processedString,
);
});
}
return _processedString;
}
/// G - a text replacing method to easily replace a given subString from a string with another value
static String _replaceSubStringWith({#required String subStringToReplace, #required String replacement, #required String input}){
final String _output = input.replaceAll(subStringToReplace, replacement);
return _output;
}
}
class SpecialWord{
final String id;
final String substitute; // you can change this to be more complex to adapt to many languages or other things
const SpecialWord({
#required this.id,
#required this.substitute,
});
/// lets create a list of constants that u may change in future and call from db or wherever
static const List<SpecialWord> _allSpecialWords = const <SpecialWord>[
SpecialWord(id: '#VAR01', substitute: 'Baby'),
SpecialWord(id: '#VAR02', substitute: 'Cool'),
SpecialWord(id: '#VAR03', substitute: 'You got the Idea'),
];
/// I like to pamper myself with super quick methods to be clean and organized
static SpecialWord getSpecialWordFromAllSpecialWordsByID(String id){
SpecialWord _foundWord;
if (id != null){
_foundWord = _allSpecialWords.firstWhere((word) => word.id == id, orElse: () => null);
}
return _foundWord;
}
}
then lets make a little method test to assure the safety of this boiler plate over engineered code
test("Testing JSON Variables work around idea", () async {
String _rawString = "This is #VAR01 app text #VAR02.";
String _processedString = JSONWorkAround.processJSONStringThatContainsThoseSpecialVariables(_rawString);
String _expectation = "This is Baby app text Cool.";
expect(_processedString, _expectation);
});
But now you might ask yourself,, is it worth it,, did I over engineer things,, is there a wiser solution ?,, maybe just save each case in json from the start,, I don't know,,
I'm afraid I over complicated the solution,, but it works like a charm

I am not sure i understood your issue. But try the following.
Add two translations one for the empty argument someAppTextEmpty and one for the regular one someAppText
{
"someAppText": "This is {} app text {}.",
"someAppTextEmpty": "This is the alternative app text."
}
Then check if the argument is empty or not to get the right translation key:
final String translationKey = argument.isNotEmpty
? 'someAppText' : 'someAppTextEmpty';
Then pass the variable translationKey to the translation function of easy_localization like this:
final String title = tr(translationKey);
// Or
Text(translationKey).tr();
// Or
translationKey.tr();

No.
With or without easy_localization, the backspace character in Dart takes 1 space in a String instead of deleting 1 space. That is my conclusion through trial and error.
My suggestion:
Create a string called BACKSPACE with a never used value starting by a space eg:
final String BACKSPACE = 'NEVER_USED_VALUE';
When appropriate, assign BACKSPACE to value1 and value2 instead of an empty string.
Then, do this:
'someAppText'.tr(value1, value2).replaceAll(' ' + BACKSPACE, '');

Related

EF Core 7 can't deserialize dynamic-members in JSON column

I am trying to map my Name column to a dynamic object. This is how the raw JSON data looks (note that this is SQL-morphed from our old relational data and I am not able to generate or interact with this column via EF Core):
{ "en": "Water", "fa": "آب", "ja": "水", ... }
Just to note, available languages are stored in a separate table and thus are dynamically defined.
Through T-SQL I can perfectly interact with these objects eg
SELECT *
FROM [MyObjects]
WHERE JSON_VALUE(Name, '$.' + #languageCode) = #searchQuery
But it seems EF Core doesn't want to even deserialize these objects as whole, let alone query them.
What I get in a simple GetAll query is an empty Name. Other columns are not affected though.
I have tried so far
Using an empty class with a [JsonExtensionData] dictionary inside
Using a : DynamicObject inheritance and implementing GetDynamicMembers, TryGetMember, TrySetMember, TryCreateInstance
Directly mapping to a string dictionary.
Combining 1 & 2 and adding an indexer operator on top.
All yield the same results: an empty Name.
I have other options like going back to a junction table relational which I have many issues with, hardcoding languages which is not really intuitive and might cause problems in the future, using HasJsonConversion which basically destroys the performance on any search action... so I'm basically stuck here with this.
I think currently it's not fully supported:
You can not use dynamic operations on an expression tree like a Select statement because it needs to be translated.
JsonValue and JsonQuery requires a path to be resolved.
If you specify OwnsOne(entity = >entity.owned, owned => owned.ToJson()) and the Json could not be parsed you will get an error.
I suggest this workaround while the EF team improves the functionality.
Create a static class with static methods to be used as decoys in the expression tree. This will be mapped to the server built-in functions.
public static class DBF
{
public static string JsonValue(this string column, [NotParameterized] string path)
=> throw new NotSupportedException();
public static string JsonQuery(this string column, [NotParameterized] string path) => throw new NotSupportedException();
}
Include the database functions on your OnModelCreating method.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDbFunction(
typeof(DBF).GetMethod(nameof(DBF.JsonValue))!
).HasName("JSON_VALUE").IsBuiltIn();
modelBuilder.HasDbFunction(
typeof(DBF).GetMethod(nameof(DBF.JsonQuery))!
).HasName("JSON_QUERY").IsBuiltIn();
/// ...
modelBuilder.Entity(entity => {
//treat entity as text
entity.Property(x => x.Metadata)
.HasColumnType("varchar")
.HasMaxLength(8000);
});
}
Call them dynamically with LINQ.
var a = await _context.FileInformation
.AsNoTracking()
.Where(x => x.Metadata!.JsonValue("$.Property1") == "some value")
.Select(x => x.Metadata!.JsonValue("$.Property2"))
.ToListAsync();
You can add casts or even build anonymous types with this method.
My solution was I added a new class which has KEY and VALUE , which will represent the dictionary i needed :
public class DictionaryObject
{
public string Key { set; get; }
public string Value { set; get; }
}
and instead of having this line in the JSON class :
public Dictionary<string, string> Name { get; set; }
I changed to :
public List<DictionaryObject> Name { get; set; }
Hope it helps.

Find string length without using builtin string.length method in web methods?

I want to find length of given string with out using pub.string.length (built in function) in web methods .
Ex:If we give name "abcdef" i want result like 6 .
You could write your own java service, but that sounds redundant to me.
Here's an (as yet untested) code sample:
public static final void checkStringSize(IData pipeline)
throws ServiceException {
// pipeline
IDataCursor pipelineCursor = pipeline.getCursor();
String inputString = IDataUtil.getString( pipelineCursor, "inputString" );
pipelineCursor.destroy();
long length = -1;
length = inputString.length();
// pipeline
IDataCursor pipelineCursor_1 = pipeline.getCursor();
IDataUtil.put( pipelineCursor_1, "length", ""+length );
pipelineCursor_1.destroy();
}
You could manually count the length of the string by using pub.string:substring until it gets an error.
I wouldn't recommend this - it's inelegant, possibly quite slow and it still uses a function from pub.string, which you appear to be avoiding.
Anyway, here's a way to do it, click the link to see the image.
webMethods code sample - https://i.stack.imgur.com/FE9oU.jpg
Just make sure the input string cannot be null - otherwise the substring won't throw an error and it will have an infinite loop.

Can you combine named parameter with short-hand constructor parameter?

In dart:
Named parameters function like so-
String send(msg, {rate: 'First Class'}) {
return '${msg} was sent via ${rate}';
}
// you can use named parameters if the argument is optional
send("I'm poor", rate:'4th class'); // == "I'm poor was sent via 4th class"
Short-hand constructor parameters function like so-
class Person {
String name;
// parameters prefixed by 'this.' will assign to
// instance variables automatically
Person(this.name);
}
Is there any way to do something like the below?-
class Person{
String name;
String age;
Person({this.name = "defaultName", this.age = "defaultAge"});
}
//So that I could do something like:
var personAlpha = new Person(name: "Jordan");
Thanks,
Code samples borrowed from dartlang synonyms
Update
Yes, the = is allowed in Dart 2 and is now preferred over the : to match optional positional parameters.
Person({this.name = "defaultName", this.age = "defaultAge"});
Old Answer
You just have to use a colon instead of equals
class Person {
String name;
String age;
Person({this.name: "defaultName", this.age: "defaultAge"});
}
I find this still confusing that optional parameters use = to assign defaults but named use :.
Should ask myself.
You can use the "this." syntax with all argument types.
As answered above, you need ':' for default values for named parameters.
You can even use "this." for function typed parameters:
class C {
Function bar;
C({int this.bar(int x) : foo});
static foo(int x) => x + 1;
}
You can also add an required field to skip the default initialization, like so:
class ProcessArguments {
final String logoImagePath;
final String textLogoImagePath;
ProcessArguments({required this.logoImagePath, required this.textLogoImagePath});
}

JSON Serializer is giving an issue, when the Json string contains string and array of strings

When a Json string contains 'key1:value1', this can be converted to the Dictionary type.
But in my case, it also contains an array of strings along with the above key:value, ie:
{k1:v1; "key2\":[{\"Key11\":{\"key21\":\"Val21\",\"key22\":\"val22\"}]
(The Json data contains some strings and some arrays.)
When I use Dictionary<string, string[]> or Dictionary<string, ArrayList> -- it is failing at the value as string - cannot convert string to string[], etc.
Still Dictionary<string, object> can be used, but is there any better way to handle this?
thanks
Phani
If you don't know the structure at compile-time, then there's no other way to serialize a JSON string-- it has to be Dictionary<string,object>. However, if you're using C# 4.0, you can use DynamicObject. Since dynamic typing defers type resolution until runtime, if you serialize using this approach, you can treat your serialized object as strongly-typed (albeit without compile-time support). That means you can use JSON-style dot notation to access properties:
MyDynamicJsonObject.key2
To accomplish this, you can inherit from DynamicObject, and implement the TryGetMember method (quoted from this link, which has a full implementation):
public class DynamicJsonObject : DynamicObject
{
private IDictionary<string, object> Dictionary { get; set; }
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
this.Dictionary = dictionary;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.Dictionary[binder.Name];
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return this.Dictionary.ContainsKey(binder.Name);
}
}
Note that dynamic typing currently doesn't support indexer notation, so for arrays, you'll need to implement a workaround using notation like this:
MyDynamicJsonObject.key2.Item(0)
Your example is not valid JSON, e.g. every key and value should be surrounded by ", e.g. {"k1":"v1"}, the number of opening and closing curly brackets must match, if you escape the " character by using \" you must add a another " character, e.g. "key2\""
Use a tool such as JSONLint to validate that your JSON is correct.

AS3: Is it possible to create a variable to hold instance name?

I am trying to have a more dynamic function and would like to allow the functions instance name were it outputs the text to be changeable.
for example
function example_function(url,instance_name){
instance_name.text = url;
}
example_function('www.example.com','url_txt');
example_function('www.another.com','more_txt');
Is this possible?
Yes, just parse the string into square brackets next to the instance's owner. For example:
this[instance_name].text = url;
More info:
Take this object:
var obj:Object = {
property1: 10,
property2: "hello"
};
Its properties can be accessed either as you'd expect:
obj.property1;
obj.property2;
Or as mentioned above:
obj["property1"];
obj["property2"];
I suggest using a function like this one I've created to tighten your code up a bit:
function selectProperty(owner:*, property:String):*
{
if(owner.hasOwnProperty(property)) return owner[property];
else throw new Error(owner + " does not have a property \"" + property + "\".");
return null;
}
trace(selectProperty(stage, "x")); // 0
trace(selectProperty(stage, "test")); // error
It is definitely possible, but it's not really best practice to do it with Strings like that. Instead, you can pass in a reference to the variable you're trying to modify.
function example_function(url : String, instance : TextField) : void {
instance.text = url;
}
example_function("www.example.com", url_txt);
This gives you strong typing so you can tell at compile time if you're operating on a TextField or not. If you aren't, you'll get an error because the 'text' property doesn't exist. You'll be able to find and track down errors faster this way.
However, if you must do it with Strings, you can access any property on any object using a string key like:
var myInstance = this[instance_name]
So in your example, you could do:
function example_function(url : String, instance : TextField) : void {
this[instance_name].text = url;
}
example_function("www.example.com", "url_txt");