Add support for conditions

This commit is contained in:
david-swift 2024-03-02 16:57:56 +01:00
parent 3a0eda789f
commit f498347485
6 changed files with 78 additions and 48 deletions

View File

@ -44,6 +44,16 @@ Generate the variables for the translations.
- defaultLanguage: The default language.
- Returns: The syntax.
### `parseValue(defaultTranslation:translations:language:arguments:)`
Parse the content of a switch case.
- Parameters:
- defaultTranslation: The translation without any conditions (always required).
- translations: All the available translations for an entry.
- language: The language.
- arguments: The arguments of the entry.
- Returns: The syntax.
### `generateLanguageFunction(dictionary:defaultLanguage:)`
Generate the function for getting the translated string for a specified language code.

View File

@ -27,6 +27,12 @@ house:
en: House
de: Haus
fr: Maison
houses(count):
en(count == "1"): There is one house.
en: There are (count) houses.
de(count == "1"): Es gibt ein Haus.
de: Es gibt (count) Häuser.
```
Then, access the localized strings safely in your code:
@ -35,6 +41,7 @@ Then, access the localized strings safely in your code:
// Use the system language
print(Loc.hello(name: "Peter"))
print(Loc.house)
print(Loc.houses(count: "1"))
// Access the translation for a specific language
print(Localized.hello(name: "Peter").en)
@ -70,11 +77,13 @@ export:
de: Exportiere das Dokument
send(message, name):
en(name == ""): Send (message).
en: Send (message) to (name).
de: Sende (message) to (name).
```
As you can see, you can add parameters using brackets after the key.
As you can see, you can add parameters using brackets after the key,
and conditions using brackets after the language (e.g. for pluralization).
The line `default: en` sets English as the fallback language.

View File

@ -151,13 +151,18 @@ public enum Generation {
guard let valueForLanguage = entry.value[language] ?? entry.value[defaultLanguage] else {
throw GenerationError.missingTranslationInDefaultLanguage(key: key.0)
}
let value = parseValue(
defaultTranslation: valueForLanguage,
translations: entry.value,
language: language,
arguments: key.1
)
if key.1.isEmpty {
variable += indent("\ncase .\(entry.key):", by: indentTwo)
variable += indent("\n\"\(valueForLanguage)\"", by: indentThree)
variable += value
} else {
let translation = parse(translation: valueForLanguage, arguments: key.1)
variable += indent("\ncase let .\(entry.key):", by: indentTwo)
variable += indent("\n\"\(translation)\"", by: indentThree)
variable += value
}
}
variable += indent("\n }\n}", by: indentOne)
@ -169,6 +174,42 @@ public enum Generation {
return result
}
/// Parse the content of a switch case.
/// - Parameters:
/// - defaultTranslation: The translation without any conditions (always required).
/// - translations: All the available translations for an entry.
/// - language: The language.
/// - arguments: The arguments of the entry.
/// - Returns: The syntax.
static func parseValue(
defaultTranslation: String,
translations: [String: String],
language: String,
arguments: [String] = []
) -> String {
var value = "\n"
let conditionTranslations = translations.filter { $0.key.hasPrefix(language + "(") }
let lastTranslation = parse(translation: defaultTranslation, arguments: arguments)
if conditionTranslations.isEmpty {
return indent("\n\"\(lastTranslation)\"", by: indentThree)
}
for translation in conditionTranslations {
var condition = translation.key.split(separator: "(")[1]
condition.removeLast()
value.append(indent("""
if \(condition) {
\"\(parse(translation: translation.value, arguments: arguments))\"
} else
""", by: indentThree))
}
value.append("""
{
\"\(lastTranslation)\"
}
""")
return value
}
/// Generate the function for getting the translated string for a specified language code.
/// - Parameters:
/// - dictionary: The parsed YML.
@ -199,7 +240,7 @@ public enum Generation {
static func getLanguages(dictionary: [String: [String: String]]) -> [String] {
var languages: Set<String> = []
for key in dictionary {
languages = languages.union(key.value.map { $0.key })
languages = languages.union(key.value.compactMap { $0.key.components(separatedBy: "(").first })
}
return .init(languages)
}

View File

@ -10,6 +10,16 @@ house:
de: Haus
fr: Maison
houses(count):
en(count == "1"): There is one house.
en(count == "0"): There is no house.
en: There are (count) houses.
de(count == "1"): Es gibt ein Haus.
de(count == "0"): Es gibt kein Haus.
de: Es gibt (count) Häuser.
# There is no French translation for this phrase.
# The default language, in this case English, will be used.
helloPair(name1, name2):
en: Hello, (name1) and (name2)!
de: Hallo, (name1) und (name2)!

View File

@ -20,6 +20,9 @@ enum Tests {
print("DE_CH: \(Localized.house.string(for: "de_CH"))")
print("SYSTEM: \(Localized.house.string)")
print("EN: \(Localized.helloPair(name1: "Max", name2: "Ruedi").en)")
print(Loc.houses(count: "0"))
print(Loc.houses(count: "1"))
print(Loc.houses(count: "2"))
}
}

View File

@ -1,43 +0,0 @@
//
// Tests.swift
// Localized
//
// Created by david-swift on 27.02.2024.
//
import Foundation
import Localized
#localized(default: "en", yml: """
hello(name):
en: Hello, (name)!
de: Hallo, (name)!
fr: Salut, (name)!
house:
en: House
de: Haus
fr: Maison
helloPair(name1, name2):
en: Hello, (name1) and (name2)!
de: Hallo, (name1) und (name2)!
fr: Salut, (name1) et (name2)!
""")
/// Test cases for the `localized` macro.
@main
enum Tests {
/// Test the `localized` macro.
static func main() {
print("EN: \(Localized.hello(name: "Peter").en)")
print("DE: \(Localized.hello(name: "Ruedi").de)")
print("SYSTEM: \(Loc.hello(name: "Sams"))")
print("FR: \(Localized.house.fr)")
print("DE_CH: \(Localized.house.string(for: "de_CH"))")
print("SYSTEM: \(Localized.house.string)")
print("EN: \(Localized.helloPair(name1: "Max", name2: "Ruedi").en)")
}
}