How to localize title and description? (LocalizedStringResource) - swift

I am working on my SwiftUI project and added some AppIntents for the Shortcuts app. Currently I am not able to localize the title and description. The title and the description are of type LocalizedStringResource (available from iOS16+).
I tried to localize the following code to German, but I don't know how to do it.
struct Add_Memory_Shortcut: AppIntent {
// The name of the action in Shortcuts
// TODO: Localization
static var title : LocalizedStringResource = "Create Memory"
// Description of the action in Shortcuts
// Category name allows you to group actions - shown when tapping on an app in the Shortcuts library
static var description: IntentDescription = IntentDescription("Create a new memory", categoryName: "Creating")
}
Any help or link is appreciated. Thanks :)

I tried everything, only one thing works, add your localization strings in
Localizable.strings
And if you want to localize string with paramter
//Localizable.strings
"hello_user%#" = "Hello %#";
//Your AppIntents
let welcomeMSG = LocalizedStringResource("hello_user\(userName)")

LocalizedStringResource doesn't have a ton of documentation available, but take a look at https://developer.apple.com/documentation/foundation/localizedstringresource/3988421-init:
init(
_ keyAndValue: String.LocalizationValue,
table: String? = nil,
locale: Locale = .current,
bundle: LocalizedStringResource.BundleDescription = .main,
comment: StaticString? = nil
)
For table, it says: "The name of the table containing the key-value pairs. If not provided, nil, or an empty string, this value defaults to Localizable.strings." In my experience that's not currently true, and you may need to explicitly point it to your translations, e.g.:
let myString = LocalizedStringResource("Hello, big world!", table: "Localizable.strings")
If you do that, supply appropriate translations, and set a locale that matches, you will see the localized version presented -- at least within a SwiftUI view:
Text(myString)

Related

In Swift a block to process an html string enters an infinite loop and causes app to break

In my iOS app, I have an auxiliary function that receives an html-formatted string and removes the explicit height tags from images.
This is the complete function:
/// This function removes any explicit height in image tag
/// - Parameter htmlString: target HTML
/// - Returns: string HTML after removing height from any aimge tag
private func removeExplicitHeightFromImgTag(for htmlString: String) -> String {
var result = NSString(string: htmlString)
/// Potential breakpoint / Infinite look: This while loop seems to be causing infinite loop behaviour.
while let imagTagrange = (result as String).firstRangeThatMatches(for: "<img.*height\\s*=\\s*(\\\")?[0-9]+(\\\")?") {
let imageTag = result.substring(with: imagTagrange)
if let heightRange = imageTag.firstRangeThatMatches(for: "height\\s*=\\s*(\\\")[0-9]+(\\\")?") {
let tagWithoutHeight = NSString(string: imageTag).replacingCharacters(in: heightRange, with: "")
result = result.replacingCharacters(in: imagTagrange, with: tagWithoutHeight) as NSString
}
}
return result as String
}
The specific block that seems to be causing havoc is the following:
/// Potential breakpoint / Infinite look: This while loop seems to be causing infinite loop behaviour.
while let imagTagrange = (result as String).firstRangeThatMatches(for: "<img.*height\\s*=\\s*(\\\")?[0-9]+(\\\")?") {
let imageTag = result.substring(with: imagTagrange)
if let heightRange = imageTag.firstRangeThatMatches(for: "height\\s*=\\s*(\\\")[0-9]+(\\\")?") {
let tagWithoutHeight = NSString(string: imageTag).replacingCharacters(in: heightRange, with: "")
result = result.replacingCharacters(in: imagTagrange, with: tagWithoutHeight) as NSString
}
}
The input for this function would be an html block encoded as string, which represents the body of an online article.
For example, the following url: https://www.architecturaldigest.com/story/inside-an-art-filled-hollywood-regency-pied-a-terre
Would be parsed and assigned to the htmlString parameter as:
<div><p>Busting a move to Los Angeles seemed only natural for Houston-based interior designer Garrett Hunter and architect Michael Landrum. Although the two friends maintain independent practices, they share an office space and frequently collaborate on projects. The two are also partners in an ever-evolving, experimental gallery/showroom project that first came to life in Houston in 2016 named Tienda X. Two years later, Hunter and Landrum moved the gallery—which hosts a compelling mix of fine and decorative art spanning the contemporary and the antique—to a Mediterranean-style stone house in Austin. They dubbed the operation Villa X.</p><span><img alt=\"pIn a sitting room a Maison Jansen sofa is accompanied by indigo pillows by Christopher Wrobleski a Spanish Majolica oil...\" src=\"https://media.architecturaldigest.com/photos/601c24457d77c6f2f298922d/master/w_1600%2Cc_limit/2020-11-12-Watsonia-AD0080_r2.jpg\"></span><span><p>In a sitting room...
Could you please help in understanding how to solve this and if there is a way to proceed?
I am really stuck and would be enormously grateful to you :)

How can I create a function that automatically takes data from Google Sheets and replaces the tags in a Slides template?

I am new to Google Apps Script and coding in general and wasn't entirely sure how to do this. I want to create code that allows me to create a new set of Google Slides based on a Slides template using the relevant rows from a Google Sheets document.
function generateNewSlides() {
var wsID = "would insert worksheet URL ID here";
var ws = SpreadsheetApp.openById(wsID).getSheetByName("Data");
var data = ws.getRange(2, 1, ws.getLastRow()-1, 5).getValues();
>the above should get the relevant table from the sheet
data.forEach(function(info){
if(info[0]){
var firstname = info[0];
var surname = info[1];
var email = info[2];
var phone = info[3];
var image = info[4];
var presName = info[5];
>the above are columns where the different pieces of data would be taken from for the placeholders in the Slides template
var slidesTemplateID = "would insert slides template URL ID here";
var slidesTemplate = SlidesApp.openById(slidesTemplateID);
var template = slidesTemplate.getSlides();
var folderID = "would insert desired folder ID for saving in here";
>the above should get me the Slides template
template.makeCopy(presName,DriveApp.getFolderById(folderID)); **>line where error occurred**
var newPresentation = DriveApp.getFilesByName(presName).next().getUrl();
var Presentation = SlidesApp.openByUrl(newPresentation);
>the above should create a copy and then open it
var shapes = (Presentation.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{firstname}}',firstname);
shape.getText().replaceAllText('{{surname}}',surname);
shape.getText().replaceAllText('{{email}}',email);
shape.getText().replaceAllText('{{phone}}',phone);
shape.getText().replaceAllText('{{presname}}', presName)
});
>the above should replace all the placeholder tags in the template with the row data
}
});
}
Above is the code I have so far. The worksheet I am extracting data from has columns: first name, surname, email address, phone number, image (URL), and presentation name. When I try to run it I encounter an error on line 37 where it says template.makeCopy is not a function, however I am certain .makeCopy should be able to create a copy for it, no?
My main questions are:
1) What should I change to make it work, generating a new set slides for each row in the worksheet?
2) How can I add images to it replacing placeholder tags I've added in squares (not textboxes) in the template?
Thanks in advance!
Issue 1. makeCopy:
makeCopy(name, destination) is a method of the class File, which belongs to the Drive Service, not to the Slides Service. In your code, template is a list of Slides (you retrieve it by calling the method getSlides() from a Presentation). makeCopy cannot work here.
In order to make a copy of a Presentation, you should be using the Drive Service instead. You should replace these lines:
var slidesTemplate = SlidesApp.openById(slidesTemplateID);
var template = slidesTemplate.getSlides();
With this one:
var template = DriveApp.getFileById(slidesTemplateID);
Issue 2. Iterating through all shapes:
Next, you want to iterate through all shapes in your Presentation, and replace all placeholder tags with your desired text. In order to do that, you are using Presentation.getShapes(), which cannot work, since getShapes() is not a method of Presentation, but of Slide.
You should first iterate through all Slides in the Presentation, and for each Slide, iterate through all Shapes. You should replace these lines:
var shapes = (Presentation.getShapes());
shapes.forEach(function(shape){
// Replacing text lines
});
With these ones:
Presentation.getSlides().forEach(function(slide) {
slide.getShapes().forEach(function(shape) {
// Replacing text lines
})
});
Note:
In order to retrieve the copied presentation, you are currently doing this:
template.makeCopy(presName,DriveApp.getFolderById(folderID));
var newPresentation = DriveApp.getFilesByName(presName).next().getUrl();
var Presentation = SlidesApp.openByUrl(newPresentation);
There is no need to do this, you can just retrieve the ID of the created template, and open by ID, like this:
var copiedTemplate = template.makeCopy(presName,DriveApp.getFolderById(folderID));
var Presentation = SlidesApp.openById(copiedTemplate.getId());
Reference:
Slides Service
Drive Service

Localization for the words "minutes" and "seconds" in countDownTimerLabel

I localised almost all labels and buttons. However, when I localise my timerLabel, the words "min" and "sec" are not translated in other language. Here's the timer function.
enter image description here
In order to localise countDownLabel, I used this localisation method below.
func setUpTranslation() {
countDownLabel.text = NSLocalizedString("CountDown", comment: "")
}
I tried to set "CountDown" key for the countDownLabel in Localizable.strings(Spanish) like these below one by one. But they didn't work.
"CountDown" = "(%d)min(%d)seg"
"CountDown" = "(minutes)min(seconds)seg"
"CountDown" = "%dmin%dseg"
"CountDown" = "\(%d)min\(%d)seg"
Would you tell me whether there is any other sign that I need to add to successfully translate those words or not?

Can you extract the text from a CLKRelativeDateTextProvider?

I'm building up a set of Complications and have come to the CLKComplicationTemplateUtilitarianLargeFlat which only has one textProvider.
I want to display some text, along with a relative date. So I tried doing this:
let date = CLKRelativeDateTextProvider(date: NSDate(), style: style, units: units)
let template = CLKComplicationTemplateUtilitarianLargeFlat()
template.textProvider = CLKSimpleTextProvider(text: "next: \(date)")
But all I get is:
<CLKRelativeDateTextProvider: 0x79860b80>
Can you extract the raw text from the CLKRelativeDateTextProvider or combine it with a CLKSimpleTextProvider in some way?
Pass in the CLKRelativeDateTextProvider object to the format string, as mentioned in Apple's code:
#interface CLKTextProvider : NSObject <NSCopying>
// By passing one or more CLKTextProviders in the format substitutions, you can add text around the output of a text provider.
+ (CLKTextProvider *)textProviderWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
#property (nonatomic) UIColor *tintColor;
#end
Here is an example:
id relativeDate = [CLKRelativeDateTextProvider textProviderWithDate:[NSDate dateWithTimeIntervalSinceNow:12 * 60]
style:CLKRelativeDateStyleNatural
units:NSCalendarUnitMinute];
template.textProvider = [CLKTextProvider textProviderWithFormat:#"next: %#", relativeDate];
The time shown in the date provider will still update as time passes without having to refresh anything.
With the current version of ClockKit you can not pull any String data from a text provider nor combine 2 or more text providers. The only text providers available to you are:
CLKDateTextProvider
CLKRelativeDateTextProvider
CLKSimpleTextProvider
CLKTimeIntervalTextProvider
CLKTimeTextProvider
To answer your question you will not be able to display the word "Next" and then a date in your complication. Due to the way ClockKit is designed and the way your complication data should be designed, however, you shouldn't be needing to display "Next" at all. Your complication should be automatically showing the next item from your data relative to the current time.

how to detect if a mobile supports unicode of a particular language in J2ME

I am designing an application in J2me, where I just have to give interface in a Particular language, say Urdu. What I am doing is using Unicode characters to print labels, like "Welcome" into my language, and its displaying the right way.
As this application is supposed to run on different mobile models, I just want to know that if it's programmatic-ally possible to check that if a particular mobile running my application does support unicode of my language? because if it doesn't then it shall show labels in default English language. I didn't code it yet except the conversion of English Alphabets to my language characters, I just want to know and if possible to find a way to perform this check. Thanks in advance :)
There is a System property where you can read the current language selected on the handset.
String locale = System.getProperty("microedition.locale");
The first two letters identify the language while the last two letters identify the country. For example, "en-US" represents English on United States of America, while "pt-BR" represents Portuguese on Brazil.
A good thing is to have all your GUI Strings loaded based on the current language.
Lets say you store all those Strings in a single array and initialize it like this:
String messages [] = null;
if (locale.startsWith("pt")) {
messages = new String [] {
"Novo Jogo",
"Configurações",
"Ajuda"
};
} else { // default language is English
messages = new String [] {
"New Game",
"Settings",
"Help"
};
}
Then you define some constants to identify each index.
static final int MSG_NEW_GAME = 0;
static final int MSG_SETTINGS = 1;
static final int MSG_HELP = 2;
And use them like this (where menuList is an instance of List):
menuList.append(messages[MSG_NEW_GAME], null);
menuList.append(messages[MSG_SETTINGS], null);
menuList.append(messages[MSG_HELPS], null);
With this you have support for two languages in your application. The more cases you have for messages initiation based on locale, the better for your end user.
As seen at http://smallandadaptive.blogspot.com.br/2008/12/internationalization-or-just-i18n-count.html