Localization support for string interpolation


(Daniel Höpfl) #1

Hi there!

TL;DR: Here’s my idea for a better localized strings handling in Swift.
It includes both, support for string interpolation support for
NSLocalizedString, and a new string delimiter `...` that can be used
instead of NSLocalizedString("...").

Markdown hard to read? See
<https://gist.github.com/dhoepfl/203f8b9bb8014593772a3b12d807ebce>

Greetings,
   Daniel

# Localization support for string interpolation

## Introduction

I'd like to see some kind of advanced localization support in the Swift
standard library. Currently all we have is what Cocoa provides but that
does not work well with string interpolation. More or less, you can not
use string interpolation if you have to use `NSLocalizedString` and friends.

[I implemented a proof of
concept](https://github.com/dhoepfl/DHLocalizedString),
`DHLocalizedString`, that fills this gap. I would like to see something
similar being part of the Swift standard library. While it is possible
to implement localized strings as a custom library, this lacks support
from genstring and other tools.

I’m not sure if `NSLocalizedString` is considered part of the Swift
standard library (being part of Foundation Functions). Since there is
decent Unicode-string support in Swift, I would like to see localization
as part of the language, too. This proposal also includes a new string
delimiter `` ` `` that deeply integrate localized strings in the language.

## Motivation

String interpolation greatly simplyfies text handling but makes it hard
to localize. You can not pass a string with interpolation to
`NSLocalizedString` because the key could be unpredictable.

## Proposed solution

`NSLocalizedString` should be extended to work with string interpolation:

let quote = "Never trust the internet!"
let person = "Albert Einstein"
print(NSLocalizedString("<\(quote)> by <\(person)>"));

should look up the key:

"<%@> by <%@>" = "%2$@ said: “%1$@”";

and print:

Albert Einstein said: “Never trust the internet!”

So, `NSLocalizedString` (and friends) would “just work” with string
interpolation. I’m not sure about the key format to use but my proof of
concept simply replaces every interpolation with `%@` which seems
reasonable.

The proof of concept also includes an postfix operator `|~` (think of a
flag) to reduce the impact localized strings have in line length.
Actually, I would love to replace `"` by a different marker (e.g.
`~|string|~`, `''string''`, ``` ``string`` ```, or `` `string` ``?) for
localized strings. Imagine you could write the previous example as:

print(`<\(quote)> by <\(person)>`);

This syntax needs some work on how to specify `tableName:`, `bundle:`,
and `comment:`. For `tableName:` and `bundle:`, I'd love to have a
construct to specify it for all localization tags within the file (e.g.
`#localization(tableName: ..., bundle: ...)`).

If Swift gets multiline strings (`"""string"""`), `` `string` `` could
also have ```` ```multiline``` ````.

## Impact on existing code

I see very little impact. There might be code out there that uses a
interpolated string as argument for `NSLocalizedString`. The key used in
this case would change, breaking the translation. It would be possible
to include a check for interpolated strings as arguments to
`NSLocalizedString` calls in the code update tool.

## Alternatives considered

### Use `NSLocalizedString` as is

One can use `NSLocalizedString` as it was used in Objective-C but this
means that string interpolation cannot be used.

### `localized()` function for String class

I did not find a way how to get the function called before the string
interpolation took place. (`"<\(quote)> by <\(person)>".localized()`)

### Custom function

See above: The drawbacks are: Not having support in standard tools and
the operator syntax not being as good as it could be.


(Daniel Höpfl) #2

Hi Adrian,

"\(key)" is already part of Swift (see <https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID285>).

Maybe using "<\(quote)> by <\(person)>" as example was not the best idea, I should have used "“\(quote)” by \(person)". I changed the gist accordingly.

···

On 2016-04-21 11:21, Adrian Zubarev wrote:

I took a quick look at your proposal and one thing I didn’t liked
was the string itsel: "some text <\(key)>“

This looks odd to me. I’d suggest something like "some text
@(key)“ or "some text \[key]“ instead. But it is not up to me.

--
Adrian Zubarev
Am 21. April 2016 bei 09:42:18, Daniel Höpfl via swift-evolution
(swift-evolution@swift.org) schrieb:

Hi there!

TL;DR: Here’s my idea for a better localized strings handling in
Swift.
It includes both, support for string interpolation support for
NSLocalizedString, and a new string delimiter `...` that can be used
instead of NSLocalizedString("...").

Markdown hard to read? See
<https://gist.github.com/dhoepfl/203f8b9bb8014593772a3b12d807ebce>

Greetings,
Daniel

# Localization support for string interpolation

## Introduction

I'd like to see some kind of advanced localization support in the
Swift
standard library. Currently all we have is what Cocoa provides but
that
does not work well with string interpolation. More or less, you can
not
use string interpolation if you have to use `NSLocalizedString` and
friends.

[I implemented a proof of
concept](https://github.com/dhoepfl/DHLocalizedString),
`DHLocalizedString`, that fills this gap. I would like to see
something
similar being part of the Swift standard library. While it is
possible
to implement localized strings as a custom library, this lacks
support
from genstring and other tools.

I’m not sure if `NSLocalizedString` is considered part of the
Swift
standard library (being part of Foundation Functions). Since there
is
decent Unicode-string support in Swift, I would like to see
localization
as part of the language, too. This proposal also includes a new
string
delimiter `` ` `` that deeply integrate localized strings in the
language.

## Motivation

String interpolation greatly simplyfies text handling but makes it
hard
to localize. You can not pass a string with interpolation to
`NSLocalizedString` because the key could be unpredictable.

## Proposed solution

`NSLocalizedString` should be extended to work with string
interpolation:

let quote = "Never trust the internet!"
let person = "Albert Einstein"
print(NSLocalizedString("<\(quote)> by <\(person)>"));

should look up the key:

"<%@> by <%@>" = "%2$@ said: “%1$@”";

and print:

Albert Einstein said: “Never trust the internet!”

So, `NSLocalizedString` (and friends) would “just work” with
string
interpolation. I’m not sure about the key format to use but my
proof of
concept simply replaces every interpolation with `%@` which seems
reasonable.

The proof of concept also includes an postfix operator `|~` (think
of a
flag) to reduce the impact localized strings have in line length.
Actually, I would love to replace `"` by a different marker (e.g.
`~|string|~`, `''string''`, ``` ``string`` ```, or `` `string` ``?)
for
localized strings. Imagine you could write the previous example as:

print(`<\(quote)> by <\(person)>`);

This syntax needs some work on how to specify `tableName:`,
`bundle:`,
and `comment:`. For `tableName:` and `bundle:`, I'd love to have a
construct to specify it for all localization tags within the file
(e.g.
`#localization(tableName: ..., bundle: ...)`).

If Swift gets multiline strings (`"""string"""`), `` `string` ``
could
also have ```` ```multiline``` ````.

## Impact on existing code

I see very little impact. There might be code out there that uses a
interpolated string as argument for `NSLocalizedString`. The key
used in
this case would change, breaking the translation. It would be
possible
to include a check for interpolated strings as arguments to
`NSLocalizedString` calls in the code update tool.

## Alternatives considered

### Use `NSLocalizedString` as is

One can use `NSLocalizedString` as it was used in Objective-C but
this
means that string interpolation cannot be used.

### `localized()` function for String class

I did not find a way how to get the function called before the
string
interpolation took place. (`"<\(quote)> by
<\(person)>".localized()`)

### Custom function

See above: The drawbacks are: Not having support in standard tools
and
the operator syntax not being as good as it could be.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Uli Kusterer) #3

Daniel, thanks for posting this. As you already know from Twitter, I'm very much in favor of this proposal. I can pretty much not use string interpolation because it doesn't localize properly.

···

On 21 Apr 2016, at 09:42, Daniel Höpfl via swift-evolution <swift-evolution@swift.org> wrote:

So, `NSLocalizedString` (and friends) would “just work” with string
interpolation. I’m not sure about the key format to use but my proof of
concept simply replaces every interpolation with `%@` which seems
reasonable.

One request: Could you perhaps use positional syntax? In some languages, the word order of the placeholders needs to change, and there needs to be a way to detect that the translator swapped two placeholders. In NSLocalizedString, that is done via %1$@, %2$@.

— Uli Kusterer
“The Witnesses of TeachText are everywhere..."


(Chris Lattner) #4

FWIW, this is closely related to the idea of extending string interpolation to support generalized “printf” style modifiers, which would allow very expressive formatting inline in a string interpolation. This has not yet come to pass, but a write up of the ideas are available here:

-Chris

···

On Apr 21, 2016, at 12:42 AM, Daniel Höpfl via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

TL;DR: Here’s my idea for a better localized strings handling in Swift.
It includes both, support for string interpolation support for
NSLocalizedString, and a new string delimiter `...` that can be used
instead of NSLocalizedString("...”).


(Adrian Zubarev) #5

I know that :smiley: I mean < and > are considered as normal characters of the string "<\(quote)> by <\(person)>“ so thats why this won’t work that way.

···

--
Adrian Zubarev

Am 21. April 2016 bei 11:32:05, Daniel Höpfl via swift-evolution (swift-evolution@swift.org) schrieb:

Maybe using "<\(quote)> by <\(person)>"


(Daniel Höpfl) #6

Using it in the translated string already works (see test cases).

I assume you want it to be part of the key? Like:

    DHLocalizedString("first: \("a"), second: \("b")")

Localizable.strings:

    "first: %1$@, second: %2$@" = "vor %2$@ kommt %1$@";

Then one would have to change <https://github.com/dhoepfl/DHLocalizedString/blob/master/DHLocalizedString/DHLocalizedString.swift#L68>.

Could be done but I'm not sure if I'd like to have to include the position in the key, even if there is only one argument. Could be an exception, of course.

Greetings,
    Daniel

···

On 2016-04-21 12:41, Uli Kusterer wrote:

[...]
One request: Could you perhaps use positional syntax? In some
languages, the word order of the placeholders needs to change, and
there needs to be a way to detect that the translator swapped two
placeholders. In NSLocalizedString, that is done via %1$@, %2$@.


(Chris Lattner) #7

Actually, it looks like the interesting point didn’t make it into the formal writeup. The idea was to enable something like this (just a sketch):

public protocol CustomStringConvertible {
  /// A textual representation of `self`.
  var description: String { get }

  func formattedDescription(format: String) -> String { get }
}

Int could then implement support for “x” to print hexadecimal, we could support left/right whitespace padding, and custom types could provide their own custom formatters (e.g. a string could have a title case formatter, or a "look up localized form of” modifier). We could then provide a “printf” that would allow traditional “%x0” substitutions. It could also be incorporated into the string literal syntax by allowing something like:

  let hashValue = 42 // not a good hash function
  print(“Hashcode = \(hashValue:x)”)

This is just a sketch, but that’s the idea. It never went anywhere because we didn’t have the language features in place to make it work, notably defaulted implementations in protocols were missing at the time.

-Chris

···

On Apr 24, 2016, at 2:33 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Apr 21, 2016, at 12:42 AM, Daniel Höpfl via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

TL;DR: Here’s my idea for a better localized strings handling in Swift.
It includes both, support for string interpolation support for
NSLocalizedString, and a new string delimiter `...` that can be used
instead of NSLocalizedString("...”).

FWIW, this is closely related to the idea of extending string interpolation to support generalized “printf” style modifiers, which would allow very expressive formatting inline in a string interpolation. This has not yet come to pass, but a write up of the ideas are available here:
https://github.com/apple/swift/blob/master/docs/TextFormatting.rst


(Daniel Höpfl) #8

As I understand it, TextFormatting is focused on what happens inside the
interpolation brackets. The localization support has its focus on the
string parts outside the brackets.

I left out how to localize the parts inside the brackets on purpose
because that always involves developer’s decision. How to find the
translation of the string parts does not have to.

My proposal is just a Swiftyfied version of NSLocalizedString and, as
TextFormatting says: "Cocoa programmers can still use Cocoa localization
APIs for localization jobs"

So: Yes, these two proposals are related but IMO not that closely.

Greetings,
   Daniel

···

On 24.04.16 23:33, Chris Lattner wrote:

On Apr 21, 2016, at 12:42 AM, Daniel Höpfl via swift-evolution <swift-evolution@swift.org> wrote:

Hi there!

TL;DR: Here’s my idea for a better localized strings handling in Swift.
It includes both, support for string interpolation support for
NSLocalizedString, and a new string delimiter `...` that can be used
instead of NSLocalizedString("...”).

FWIW, this is closely related to the idea of extending string interpolation to support generalized “printf” style modifiers, which would allow very expressive formatting inline in a string interpolation. This has not yet come to pass, but a write up of the ideas are available here:
https://github.com/apple/swift/blob/master/docs/TextFormatting.rst


(Daniel Höpfl) #9

Sorry, I don't see the problem.

< and > are considered normal characters, that's fine.

The trick of DHLocalizedString is that it does not do the string interpolation. This is already handled by Swift.

If you call DHLocalizedString("<\(quote)> by <\(person)>"), the compiler generates something like:

DHLocalizedString(DHLocalizedStringStore("<",
                                          quote.description(),
                                          "> by <",
                                          person.description(),
                                          ">"),
                   tableName = nil,
                   bundle = nil)

DHLocalizedString concats the strings (stored in the DHLocalizedStringStore), replacing every even position by "%@". The resulting string is used as format argument of NSLocalizedString, using the even positions of the array as arguments. DHLocalizedString does not care about the contents of any of the strings parts.

All of this works because Swift always starts interpolated strings with a string literal, "\(4)" becomes ["", "4", ""] (not sure if it adds the empty string at the end, too). The parts that come from interpolation are always in the even positions.

My proposal has two parts:

a) Make NSLocalizedString work like DHLocalizedString does.
b) Make `xxx` a synonym to NSLocalizedString("xxx") (and give me a way to set the default values for tableName/bundle in this case)

···

On 2016-04-21 12:23, Adrian Zubarev via swift-evolution wrote:

I know that :smiley: I mean < and > are considered as normal characters of
the string "<\(quote)> by <\(person)>“ so thats why this won’t
work that way.

--
Adrian Zubarev
Am 21. April 2016 bei 11:32:05, Daniel Höpfl via swift-evolution
(swift-evolution@swift.org) schrieb:

Maybe using "<\(quote)> by <\(person)>"

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Uli Kusterer) #10

Yeah, idea here is principle of least surprise. Most lcoalization tools pre-populate the translations with the keys, so having the positional indices in there would mean nobody forgets it and then gets back a translation with the contents reversed (admittedly, since you're using the same %@ format for everything, at least your code won't crash. In ObjC, if someone swapped out a %@ and a %d, you got some "hilarious" results).

— Uli Kusterer
“The Witnesses of TeachText are everywhere..."

···

On 21 Apr 2016, at 16:21, Daniel Höpfl <daniel@hoepfl.de> wrote:

I assume you want it to be part of the key? Like:

  DHLocalizedString("first: \("a"), second: \("b")")

Localizable.strings:

  "first: %1$@, second: %2$@" = "vor %2$@ kommt %1$@";

Then one would have to change <https://github.com/dhoepfl/DHLocalizedString/blob/master/DHLocalizedString/DHLocalizedString.swift#L68>.

Could be done but I'm not sure if I'd like to have to include the position in the key, even if there is only one argument. Could be an exception, of course.


(Dave Abrahams) #11

I believe I also had concerns about this design because it needlessly
misses opportunities for compile-time type safety. There doesn't seem
to be any reason to embed the format specifier in a dynamic string that
has to be parsed at runtime.

···

on Sun Apr 24 2016, Chris Lattner <swift-evolution@swift.org> wrote:

On Apr 24, 2016, at 2:33 PM, Chris Lattner via swift-evolution > <swift-evolution@swift.org> wrote:

On Apr 21, 2016, at 12:42 AM, Daniel Höpfl via swift-evolution > <swift-evolution@swift.org> wrote:

Hi there!

TL;DR: Here’s my idea for a better localized strings handling in Swift.
It includes both, support for string interpolation support for
NSLocalizedString, and a new string delimiter `...` that can be

used

instead of NSLocalizedString("...”).

FWIW, this is closely related to the idea of extending string
interpolation to support generalized “printf” style modifiers, which
would allow very expressive formatting inline in a string
interpolation. This has not yet come to pass, but a write up of the
ideas are available here:
https://github.com/apple/swift/blob/master/docs/TextFormatting.rst

Actually, it looks like the interesting point didn’t make it into the
formal writeup. The idea was to enable something like this (just a
sketch):

public protocol CustomStringConvertible {
  /// A textual representation of `self`.
  var description: String { get }

  func formattedDescription(format: String) -> String { get }
}

Int could then implement support for “x” to print hexadecimal, we
could support left/right whitespace padding, and custom types could
provide their own custom formatters (e.g. a string could have a title
case formatter, or a "look up localized form of” modifier). We could
then provide a “printf” that would allow traditional “%x0”
substitutions. It could also be incorporated into the string literal
syntax by allowing something like:

  let hashValue = 42 // not a good hash function
  print(“Hashcode = \(hashValue:x)”)

This is just a sketch, but that’s the idea. It never went anywhere
because we didn’t have the language features in place to make it work,
notably defaulted implementations in protocols were missing at the
time.

--
Dave


(Uli Kusterer) #12

I'm not quite sure why we'd want to support printf-style syntax in the first place? Interpolation is more readable, as the formats contain their descriptive variable names, and you don't have to worry about matching up format string placeholder order and types with those of what you're actually passing. I.e. string interpolation is to printf what type inference is to explicit declarations, and what labeled parameters are to old-style C initializer lists.

So I'd say Swift should come at this from the other direction and ensure that anything you were able to do with printf is also possible with interpolation (if that means specifying some sort of format flag in-line as well, I could live with that).

I do see the utility in allowing any custom type to be printed out via interpolation though, and to allow them to at the least query the existing flags as well. But should we really use single-character flags? C++, apart from overloading bitshift, has the right idea:

  cout << "foo" << hex << 123 << "\n";

is much more readable than

  printf( "foo%x\n", 123 );

Maybe we could just use a function as the flag?

  print( "foo\(hex(123))\n" )

would then expand into "foo" hex(123) "\n", where hex would just be an object or function that takes an Int and returns a hex-formatted string? Though this'd pollute the namespace I suppose. 123.hex() maybe? Then it could be an arbitrary method on Int, added with a category.

Cheers,
-- Uli Kusterer
"The Witnesses of TeachText are everywhere..."
http://orangejuiceliberationfront.com

···

On 24 Apr 2016, at 23:40, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Int could then implement support for “x” to print hexadecimal, we could support left/right whitespace padding, and custom types could provide their own custom formatters (e.g. a string could have a title case formatter, or a "look up localized form of” modifier). We could then provide a “printf” that would allow traditional “%x0” substitutions.


(Daniel Höpfl) #13

Yeah, idea here is principle of least surprise. Most lcoalization
tools pre-populate the translations with the keys, so having the
positional indices in there would mean nobody forgets it and then
gets back a translation with the contents reversed

If you want to play around with it, I added a branch in the proof of
concept repo that uses positional arguments in the keys.

(admittedly, since
you're using the same %@ format for everything, at least your code
won't crash. In ObjC, if someone swapped out a %@ and a %d, you got
some "hilarious" results).

Correct.

While it is possible to use different placeholders (%d, %f, ...)
depending on the type of the interpolation argument, I don't think it is
worth it.

What you said is one reason, then it makes genstrings harder since
finding the type requires to parse more than just the string and while
there might be cases where you want to have e.g. "%+17.3f" in the
translated text, you normally should use a (localized) formatter here
anyways, so always having the description() here is probably okay and
makes the keys/translations more consistent.

Greetings,
   Daniel

···

On 21.04.16 18:29, Uli Kusterer wrote:


(Brent Royal-Gordon) #14

I believe I also had concerns about this design because it needlessly
misses opportunities for compile-time type safety. There doesn't seem
to be any reason to embed the format specifier in a dynamic string that
has to be parsed at runtime.

I started drafting a post yesterday making the same point, but got bogged down in writing an example of what I *would* want to see.

In brief: printf()-style specifiers are kind of awful. They're very cryptic and unnecessarily unsafe. In C, this problem is addressed by compiler warnings, but Swift already has a mechanism to detect inappropriate combinations of data and operations: the type system. We should use it here.

If we had a protocol to handle formatting, I would want the method's parameter to be of an associated type and typically be something OptionSet-like. It might even be better to structure it as some sort of Formatter protocol. If properly designed, this might allow us to leverage Foundation's existing, fully-featured formatters rather than writing new ones just for Swift.

(This would be a big new feature, so personally, I would defer it.)

···

--
Brent Royal-Gordon
Architechies


(Erica Sadun) #15

Keep in mind that succinctness is a virtue, especially when using embedded annotations. (I really liked your first go at this)
Also leveraging training and experience using the (ugly but) time-tested shorthand form is not necessarily bad. The safety
issue comes more in matching types, not in doing something like \(foo.#(%06.1f))

-- E

···

On Apr 25, 2016, at 7:15 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

I believe I also had concerns about this design because it needlessly
misses opportunities for compile-time type safety. There doesn't seem
to be any reason to embed the format specifier in a dynamic string that
has to be parsed at runtime.

I started drafting a post yesterday making the same point, but got bogged down in writing an example of what I *would* want to see.

In brief: printf()-style specifiers are kind of awful. They're very cryptic and unnecessarily unsafe. In C, this problem is addressed by compiler warnings, but Swift already has a mechanism to detect inappropriate combinations of data and operations: the type system. We should use it here.

If we had a protocol to handle formatting, I would want the method's parameter to be of an associated type and typically be something OptionSet-like. It might even be better to structure it as some sort of Formatter protocol. If properly designed, this might allow us to leverage Foundation's existing, fully-featured formatters rather than writing new ones just for Swift.


(Uli Kusterer) #16

Yeah, idea here is principle of least surprise. Most lcoalization
tools pre-populate the translations with the keys, so having the
positional indices in there would mean nobody forgets it and then
gets back a translation with the contents reversed

If you want to play around with it, I added a branch in the proof of
concept repo that uses positional arguments in the keys.

Thanks!

While it is possible to use different placeholders (%d, %f, ...)
depending on the type of the interpolation argument, I don't think it is
worth it.

Only reason I could see for doing this would be backwards compatibility if you share the same localized strings between ObjC and Swift, I don't think it's worth it just for that.

Cheers,
-- Uli Kusterer
"The Witnesses of TeachText are everywhere..."
http://orangejuiceliberationfront.com

···

On 22 Apr 2016, at 09:09, Daniel Höpfl via swift-evolution <swift-evolution@swift.org> wrote:

On 21.04.16 18:29, Uli Kusterer wrote:


(Dave Abrahams) #17

It's not a matter of type or memory safety, so maybe I should have said
that it misses opportunities for static checking. The problem is that
“.#(%06.1f)” might not apply to foo.

Also, frankly I think printf syntax is arcane and readable only to a
small fraction of developers. Take a complete read through the man page
sometime if you really want your mind blown!

If you're going to take a string interpolation approach, we can instead
know *exactly* what formatting options apply to “foo,” express them
readably, and check them at compile time.

The problem is that localization may really be incompatible with
Swift-style compile-time-checked string interpolation with embedded
formatting, because of:

1. The need to look up localized strings in tables for a given language,
   making them basically dynamic as far as the compiler is concerned.

2. The need for localizers (i.e. not the application programmer) to
   tune both the string content and how the arguments are formatted.

IMO this problem begs for a holistic solution that integrates a DSL for
localizers with language and library features in Swift.

···

on Mon Apr 25 2016, Erica Sadun <erica-AT-ericasadun.com> wrote:

On Apr 25, 2016, at 7:15 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

I believe I also had concerns about this design because it needlessly
misses opportunities for compile-time type safety. There doesn't seem
to be any reason to embed the format specifier in a dynamic string that

has to be parsed at runtime.

I started drafting a post yesterday making the same point, but got bogged down in writing an example of what I *would* want to see.

In brief: printf()-style specifiers are kind of awful. They're very
cryptic and unnecessarily unsafe. In C, this problem is addressed by
compiler warnings, but Swift already has a mechanism to detect
inappropriate combinations of data and operations: the type
system. We should use it here.

If we had a protocol to handle formatting, I would want the method's
parameter to be of an associated type and typically be something
OptionSet-like. It might even be better to structure it as some sort
of Formatter protocol. If properly designed, this might allow us to
leverage Foundation's existing, fully-featured formatters rather
than writing new ones just for Swift.

Keep in mind that succinctness is a virtue, especially when using
embedded annotations. (I really liked your first go at this) Also
leveraging training and experience using the (ugly but) time-tested
shorthand form is not necessarily bad. The safety issue comes more in
matching types, not in doing something like \(foo.#(%06.1f))

--
Dave


(Norbert Lindenberg) #18

Very true. Separating localizable strings from source code is critical to making the localization process manageable, and the syntax used in localizable strings must be easy to understand for translators, who are hardly ever engineers, or supported by the tools that translators use.

Localization of messages also has some requirements that haven’t been discussed here yet:

– Inserting a number into a sentence often requires adjusting other parts of the sentence (nouns, verbs, articles) to the number. And while English has only singular and plural, other languages distinguish more cases – up to six for Arabic.

– Inserting a name or noun into a sentence often requires adjusting other parts of the sentence to the gender of the person or noun. While in English gender usually is only reflected in pronouns, its impact is pervasive in some other languages.

– Formats for numbers and dates should be specified at a high enough level that they can be automatically translated by internationalization libraries. For example, don’t specify the order of year, month, day and the characters to be used around them; specify just whether you want to have a long or a short form and which components, and let an internationalization library handle the rest.

One well supported and commonly used library handling this is ICU with its MessageFormat class:
http://userguide.icu-project.org/formatparse/messages
http://icu-project.org/apiref/icu4c/classMessageFormat.html#details

If there is dedicated support for localizable messages in Swift, it should be at least as good as MessageFormat – and translators should have at least as strong a say in what’s good as software engineers.

Norbert

···

On Apr 26, 2016, at 16:16 , Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

Also, frankly I think printf syntax is arcane and readable only to a
small fraction of developers. Take a complete read through the man page
sometime if you really want your mind blown!

If you're going to take a string interpolation approach, we can instead
know *exactly* what formatting options apply to “foo,” express them
readably, and check them at compile time.

The problem is that localization may really be incompatible with
Swift-style compile-time-checked string interpolation with embedded
formatting, because of:

1. The need to look up localized strings in tables for a given language,
  making them basically dynamic as far as the compiler is concerned.

2. The need for localizers (i.e. not the application programmer) to
  tune both the string content and how the arguments are formatted.


(Brent Royal-Gordon) #19

– Inserting a number into a sentence often requires adjusting other parts of the sentence (nouns, verbs, articles) to the number. And while English has only singular and plural, other languages distinguish more cases – up to six for Arabic.

– Inserting a name or noun into a sentence often requires adjusting other parts of the sentence to the gender of the person or noun. While in English gender usually is only reflected in pronouns, its impact is pervasive in some other languages.

– Formats for numbers and dates should be specified at a high enough level that they can be automatically translated by internationalization libraries. For example, don’t specify the order of year, month, day and the characters to be used around them; specify just whether you want to have a long or a short form and which components, and let an internationalization library handle the rest.

This is all true, but it's also all handled by Foundation on Apple platforms and hopefully by Corelibs Foundation elsewhere. We ought to be able to hook into this existing machinery.

···

--
Brent Royal-Gordon
Architechies


(Daniel Höpfl) #20

Hi.

– Inserting a number into a sentence often requires adjusting other parts of the sentence (nouns, verbs, articles) to the number. And while English has only singular and plural, other languages distinguish more cases – up to six for Arabic.

– Inserting a name or noun into a sentence often requires adjusting other parts of the sentence to the gender of the person or noun. While in English gender usually is only reflected in pronouns, its impact is pervasive in some other languages.

– Formats for numbers and dates should be specified at a high enough level that they can be automatically translated by internationalization libraries. For example, don’t specify the order of year, month, day and the characters to be used around them; specify just whether you want to have a long or a short form and which components, and let an internationalization library handle the rest.

This is all true, but it's also all handled by Foundation on Apple platforms and hopefully by Corelibs Foundation elsewhere. We ought to be able to hook into this existing machinery.

That's what I think, too: Let Foundation handle the "how to translate",
my proposal is just "syntactic sugar".

Since I did not see any more concerns about the proposal, I'd like to
push my proposal forward. Can anyone give me a hint what to do next?
Would sending a pull request be the next step? (The evolution readme
just says "Ideas should be thoroughly discussed on the swift-evolution
mailing list first." Have we reached this point?)

Thanks for your input,
   Daniel

···

On 29.04.16 05:31, Brent Royal-Gordon via swift-evolution wrote: