diff --git a/Loop Widget Extension/Bootstrap/Localizable.xcstrings b/Loop Widget Extension/Bootstrap/Localizable.xcstrings index 7c7c01e686..38724ca277 100644 --- a/Loop Widget Extension/Bootstrap/Localizable.xcstrings +++ b/Loop Widget Extension/Bootstrap/Localizable.xcstrings @@ -1,1592 +1,4738 @@ { "sourceLanguage" : "en", "strings" : { - "---" : { + "%1$@ g" : { + "comment" : "Format string for an amount of carbohydrate in grams. (1: grams)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "--" + "value" : "%1$@ g" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ г" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ g" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "---" + "value" : "%1$@ gr" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ г" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 克" } } } }, - "-U" : { + "%1$@ U" : { + "comment" : "Reservoir entry (1: volume value)", "localizations" : { - "da" : { + "ar" : { "stringUnit" : { "state" : "translated", - "value" : "-E" + "value" : "%1$@ وحدة" } }, - "de" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "-IE" + "value" : "%1$@ U" } }, - "es" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "-U" + "value" : "%1$@ E" } }, - "fr" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "-U" + "value" : "%1$@ IE" } }, - "it" : { + "es" : { "stringUnit" : { "state" : "translated", - "value" : "-U" + "value" : "%1$@ U" } }, - "nb" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "-E" + "value" : "%1$@ U" } }, - "nl" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "-E" + "value" : "%1$@ U" } }, - "pl" : { + "he" : { "stringUnit" : { "state" : "translated", - "value" : "-J" + "value" : "U %1$@" } }, - "ro" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "-U" + "value" : "%1$@ U" } }, - "ru" : { + "it" : { "stringUnit" : { "state" : "translated", - "value" : "-Ед" + "value" : "%1$@ U" } }, - "tr" : { + "ja" : { "stringUnit" : { "state" : "translated", - "value" : "-Ü" + "value" : "%1$@ 単位" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "-U" - } - } - } - }, - "??" : { - "localizations" : { - "da" : { + "nb" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ E" } }, - "de" : { + "nl" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ E" } }, - "es" : { + "pl" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ J" } }, - "fr" : { + "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ U" } }, - "it" : { + "ro" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ U" } }, - "nb" : { + "ru" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ Ед." } }, - "nl" : { + "sk" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%@ j" } }, - "pl" : { + "sv" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ E" } }, - "ro" : { + "tr" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ Ü" } }, - "ru" : { + "uk" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ U" } }, - "tr" : { + "vi" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ U" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "??" + "value" : "%1$@ U" } } } }, - "%@" : { + "%1$@ U/h" : { + "comment" : "Format string for an insulin rate in units per hour. (1: rate)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ وحدة لكل ساعة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/hod" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ E/t" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ IE/Std" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ U/h" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ U/h" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ U/h" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/hr %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/óra" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ U/ora" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 単位/時" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ E/t" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ E/uur" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ J/h" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/h" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ U/oră" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ Ед/ч" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ J/hod" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ IE/h" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%@" + "value" : "%1$@ Ü/Sa" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/год" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/giờ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/小时" } } } }, - "%@ U" : { + "%1$@ · %2$@ in 5 min" : { + "comment" : "Under the glucose value on the Now screen: the glucose unit and how much glucose changed over 5 minutes. (1: glucose unit, e.g. mmol/L; 2: signed change, e.g. +0.3)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ خلال ٥ دقائق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · %2$@ za 5 min" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E" + "value" : "%1$@ · %2$@ på 5 min" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@ IE" + "value" : "%1$@ · %2$@ in 5 Min" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ en 5 min" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ / 5 min" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ en 5 min" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ ב-5 דק׳" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · %2$@ 5 perc alatt" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ in 5 min" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · 5分で%2$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E" + "value" : "%1$@ · %2$@ på 5 min" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E" + "value" : "%1$@ · %2$@ in 5 min" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ J" + "value" : "%1$@ · %2$@ w 5 min" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ em 5 min" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ în 5 min" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%@ ед" + "value" : "%1$@ · %2$@ за 5 мин" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%@ j" + "value" : "%1$@ · %2$@ za 5 min" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E" + "value" : "%1$@ · %2$@ på 5 min" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%@ Ü" + "value" : "%1$@ · 5 dk'da %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · %2$@ за 5 хв" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · %2$@ trong 5 phút" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U" + "value" : "%1$@ · 5分钟内%2$@" } } } }, - "%@%@" : { + "---" : { "localizations" : { - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "---" } }, - "en" : { + "de" : { "stringUnit" : { - "state" : "new", - "value" : "%1$@%2$@" + "state" : "translated", + "value" : "---" } }, - "fr" : { + "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "---" } }, - "nb" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "---" } }, - "nl" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "---" } }, - "ro" : { + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "--" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "---" + } + } + } + }, + "-U" : { + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "-E" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "-IE" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "-U" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "-U" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "-U" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "-E" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "-E" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "-J" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "-U" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "-Ед" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "-Ü" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "-U" + } + } + } + }, + "??" : { + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "??" + } + } + } + }, + "%@" : { + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + } + } + }, + "%@ U" : { + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ IE" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ J" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ ед" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ j" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ Ü" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U" + } + } + } + }, + "%@%@" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@%2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + } + } + }, + "%@U" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@IE" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@U" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@E" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@E" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@U" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@U" + } + } + } + }, + "%1$@ v%2$@" : { + "comment" : "The format string for the app name and version number. (1: bundle name)(2: bundle version)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ против %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + } + } + }, + "Add carbs" : { + "comment" : "Button on the Now screen that opens carb entry", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إضافة كارب" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Přidat sacharidy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tilføj kulhydrater" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "KH hinzufügen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar carbohidratos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lisää hiilihydraatteja" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter des glucides" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הוספת פחמימות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Szénhidrát hozzáadása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungi carboidrati" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "カーボを追加" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Legg til karbohydrater" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Koolhydraten toevoegen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj węglowodany" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar carbs" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adăugați carbohidrați" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить углеводы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pridať sacharidy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lägg till kolhydrater" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karb ekle" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додати вуглеводи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thêm Carbs" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "添加碳水" + } + } + } + }, + "Basal" : { + "comment" : "Chart callout label for the basal rate at the touched time Label of a tile showing the current basal rate (Now screen) or the day's basal insulin total (Today so far totals) Logbook filter chip: show only basal changes", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القاعدية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaalinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podstawowy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazálna" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazal" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础" + } + } + } + }, + "Bolus" : { + "comment" : "Label for bolus entry row on bolus screen\nLabel for bolus entry row on simple bolus screen\nThe label of the bolus entry button\nTitle for bolus entry screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolo" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bólus" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ボーラス" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюс" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюс" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "大剂量" + } + } + } + }, + "Closed loop · %1$@" : { + "comment" : "Status pill on the Now screen: closed loop is on and Loop last ran this long ago. (1: duration, e.g. 3m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مغلقة · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka · %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö · %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok · %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ · %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop · %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado · %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă · %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop · %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín · %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环 · %1$@" + } + } + } + }, + "Closed loop · not run yet" : { + "comment" : "Status pill on the Now screen: closed loop is on but Loop has never completed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مغلقة · لم يعمل بعد" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka · zatím neproběhla" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · ikke kørt endnu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · noch nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado · aún no se ha ejecutado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö · ei vielä ajettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée · pas encore exécuté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · טרם רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok · még nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso · non ancora eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ · 未実行" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · ikke kjørt ennå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop · nog niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta · jeszcze nie działała" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado · ainda não executou" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă · nu a rulat încă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл · ещё не запускался" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka · ešte neprebehla" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop · inte körd än" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü · henüz çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл · ще не запускався" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín · chưa chạy" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环 · 尚未运行" + } + } + } + }, + "COB" : { + "comment" : "Abbreviation for carbs on board (active carbohydrate) Abbreviation for carbs on board; label of a tile on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GA" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + } + } + }, + "Color" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Farbe" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couleur" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Farge" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kleur" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Culoare" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "颜色" + } + } + } + }, + "Date" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datum" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dato" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datum" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dată" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "日期" + } + } + } + }, + "dB" : { + "comment" : "The short unit display string for decibles", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "дБ" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "dB" + } + } + } + }, + "End" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ende" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fin" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avslutt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stop" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sfârșit" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "结束" + } + } + } + }, + "Eventual" : { + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventuel" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventuell" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventual" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Éventuel" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "סופי" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventuale" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventuell" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uiteindelijk" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Możliwy" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventual" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "В конечном итоге" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nihai" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最终" + } + } + } + }, + "Eventually" : { + "comment" : "Short label above the glucose Loop predicts at the end of its prediction, in a small tile on the widget and Live Activity. Keep it to one short word, such as 'Forecast'.", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المتوقع" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikce" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognose" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognose" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsión" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennuste" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prévision" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "תחזית" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Várható" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsione" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "予想" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognose" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognose" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognoza" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsão" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognoză" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikcia" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognos" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tahmin" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dự báo" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "预测" + } + } + } + }, + "Eventually %1$@ %2$@" : { + "comment" : "Prediction card on the Now screen: Loop's eventual predicted glucose. (1: glucose value; 2: glucose unit, e.g. mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "في النهاية %1$@ %2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nakonec %1$@ %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Med tiden %1$@ %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voraussichtlich %1$@ %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Al final %1$@ %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennuste %1$@ %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Finalement %1$@ %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventually %1$@ %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Várható %1$@ %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infine %1$@ %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "予想 %1$@ %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Omsider %1$@ %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uiteindelijk %1$@ %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Docelowo %1$@ %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "No final %1$@ %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "În cele din urmă %1$@ %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "В конечном итоге %1$@ %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nakoniec %1$@ %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Förväntat %1$@ %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nihai KŞ %1$@ %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Зрештою %1$@ %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kết quả %1$@ %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最终 %1$@ %2$@" + } + } + } + }, + "g" : { + "comment" : "The short unit display string for grams", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "г" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "gr" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "克" + } + } + } + }, + "Glucose level" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blutzuckerspiegel" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niveau de glycémie" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukosenivå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucosewaarde" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nivelul glicemiei" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖水平" + } + } + } + }, + "Glucose range" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zielbereich" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plage de glycémie" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukoseområde" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucosebereik" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intervalul glicemic" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖范围" + } + } + } + }, + "High" : { + "comment" : "Pill under the glucose value on the Now screen when glucose is above 250 mg/dL (13.9 mmol/L) Time in range band: glucose 181–250 mg/dL (10.1–13.9 mmol/L) Time-in-range band name: glucose 181–250 mg/dL (10.1–13.9 mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "مرتفع" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vysoká" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Høj" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoch" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alta" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Korkea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Élevée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "גבוה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Magas" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alta" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "高値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Høy" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoog" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wysoka" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alta" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ridicată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Высокая" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vysoká" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Högt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yüksek" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Висока" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cao" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "高" + } + } + } + }, + "Last reading %1$@ ago" : { + "comment" : "Shown on the Now screen under No reading when the latest CGM reading is too old. (1: duration, e.g. 25m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "آخر قراءة قبل %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poslední hodnota před %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seneste måling for %1$@ siden" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Letzter Wert vor %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Última lectura hace %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Viimeisin lukema %1$@ sitten" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dernière mesure il y a %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קריאה אחרונה לפני %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utolsó érték %1$@ ezelőtt" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ultima lettura %1$@ fa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "最終測定 %1$@前" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Siste måling for %1$@ siden" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Laatste waarde %1$@ geleden" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostatni odczyt %1$@ temu" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Última leitura há %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ultima citire acum %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Последнее показание %1$@ назад" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Posledná hodnota pred %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senaste värde för %1$@ sedan" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Son okuma %1$@ önce" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Останній показник %1$@ тому" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chỉ số cuối cách đây %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最后读数在 %1$@前" + } + } + } + }, + "Loop hasn't run for %1$@" : { + "comment" : "Notice title on the Now screen when Loop hasn't completed recently. (1: duration since Loop last ran, e.g. 16m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لم يعمل Loop منذ %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop neproběhl %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har ikke kørt i %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ist seit %1$@ nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop no se ha ejecutado en %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopia ei ole ajettu %1$@ aikana" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ne s'est pas exécuté depuis %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop לא רץ כבר %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop %1$@ óta nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop non eseguito da %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopが%1$@実行されていません" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har ikke kjørt på %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop heeft %1$@ niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nie działa od %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop não executa há %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nu a rulat de %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не запускался уже %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop neprebehol %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har inte körts på %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop %1$@ süredir çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не запускався вже %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop đã không chạy trong %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 已 %1$@未运行" + } + } + } + }, + "Loop Status Widget" : { + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Widget til loop-status" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop Status Widget" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Widget de Estado de Loop" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Widget d'état de Loop" + } + }, + "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "Widget di stato del ciclo" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop Status Widget" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Widżet Stanu Pętli" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Widget de stare Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Виджет состояния петли" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Döngü Durumu Widget'ı" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "Loop 状态小组件" } } } }, - "%@U" : { + "Low" : { + "comment" : "Pill under the glucose value on the Now screen when glucose is below 70 mg/dL (3.9 mmol/L) Time in range band: glucose 54–69 mg/dL (3.0–3.8 mmol/L) Time-in-range band name: glucose 54–69 mg/dL (3.0–3.8 mmol/L)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "منخفض" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nízká" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lav" + } + }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@IE" + "value" : "Niedrig" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baja" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Matala" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@U" + "value" : "Basse" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נמוך" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alacsony" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bassa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "低値" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@E" + "value" : "Lav" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@E" + "value" : "Laag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niska" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baixa" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@U" + "value" : "Scăzută" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Низкая" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nízka" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lågt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Düşük" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Низька" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thấp" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%@U" + "value" : "低" } } } }, - "%1$@ v%2$@" : { - "comment" : "The format string for the app name and version number. (1: bundle name)(2: bundle version)", + "mg/dL" : { + "comment" : "The short unit display string for milligrams of glucose per decilter", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v %2$@" + "value" : "mg/dL" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dl" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ против %2$@" + "value" : "мг/дл" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v %2$@" + "value" : "mg/dL" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dl" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "mg/dL" } } } }, - "Color" : { + "mmol/L" : { + "comment" : "The short unit display string for millimoles of glucose per liter", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" + } + }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "Farbe" + "value" : "mmol/L" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Couleur" + "value" : "mmol/L" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "Farge" + "value" : "mmol/L" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Kleur" + "value" : "mmol/L" } }, - "ro" : { + "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Culoare" + "value" : "mmol/L" } }, - "zh-Hans" : { + "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "颜色" + "value" : "mmol/L" } - } - } - }, - "Date" : { - "localizations" : { - "de" : { + }, + "ro" : { "stringUnit" : { "state" : "translated", - "value" : "Datum" + "value" : "mmol/L" } }, - "fr" : { + "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Date" + "value" : "mmol/L" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "mmol/L" } }, - "nb" : { + "sv" : { "stringUnit" : { "state" : "translated", - "value" : "Dato" + "value" : "mmol/L" } }, - "nl" : { + "tr" : { "stringUnit" : { "state" : "translated", - "value" : "Datum" + "value" : "mmol/L" } }, - "ro" : { + "vi" : { "stringUnit" : { "state" : "translated", - "value" : "Dată" + "value" : "mmol/L" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "日期" + "value" : "mmol/L" } } } }, - "dB" : { - "comment" : "The short unit display string for decibles", + "No reading" : { + "comment" : "Shown on the Now screen in place of the glucose value when there is no recent CGM reading", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "لا توجد قراءة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná hodnota" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Ingen måling" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Kein Wert" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Sin lectura" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Ei lukemaa" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Aucune mesure" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "אין קריאה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs érték" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Nessuna lettura" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "測定値なし" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Ingen måling" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Geen waarde" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Brak odczytu" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Sem leitura" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Nicio citire" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "дБ" + "value" : "Нет показаний" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Žiadna hodnota" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Inget värde" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Okuma yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає показників" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "Không có chỉ số" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "dB" + "value" : "无读数" } } } }, - "End" : { + "Open loop · %1$@" : { + "comment" : "Status pill on the Now screen: closed loop is off (Loop recommends only) and Loop last ran this long ago. (1: duration, e.g. 3m)", "localizations" : { - "de" : { + "ar" : { "stringUnit" : { "state" : "translated", - "value" : "Ende" + "value" : "حلقة مفتوحة · %1$@" } }, - "fr" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "Fin" + "value" : "Otevřená smyčka · %1$@" } }, - "nb" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "Avslutt" + "value" : "Åbent Loop · %1$@" } }, - "nl" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "Stop" + "value" : "Open Loop · %1$@" } }, - "ro" : { + "es" : { "stringUnit" : { "state" : "translated", - "value" : "Sfârșit" + "value" : "Circuito abierto · %1$@" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "结束" - } - } - } - }, - "Eventual" : { - "localizations" : { - "da" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "Eventuel" + "value" : "Avoin säätö · %1$@" } }, - "de" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Eventuell" + "value" : "Boucle ouverte · %1$@" } }, - "es" : { + "he" : { "stringUnit" : { "state" : "translated", - "value" : "Eventual" + "value" : "Open Loop · %1$@" } }, - "fr" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "Éventuel" + "value" : "Nyitott hurok · %1$@" } }, - "he" : { + "it" : { "stringUnit" : { "state" : "translated", - "value" : "סופי" + "value" : "Loop aperto · %1$@" } }, - "it" : { + "ja" : { "stringUnit" : { "state" : "translated", - "value" : "Eventuale" + "value" : "オープンループ · %1$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "Eventuell" + "value" : "Åpen Loop · %1$@" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Uiteindelijk" + "value" : "Open loop · %1$@" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Możliwy" + "value" : "Pętla otwarta · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo aberto · %1$@" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "Eventual" + "value" : "Buclă deschisă · %1$@" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "В конечном итоге" + "value" : "Открытый цикл · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorená slučka · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppen loop · %1$@" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "Nihai" + "value" : "Açık döngü · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкритий цикл · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp mở · %1$@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "最终" + "value" : "开环 · %1$@" } } } }, - "g" : { - "comment" : "The short unit display string for grams", + "Open loop · not run yet" : { + "comment" : "Status pill on the Now screen: closed loop is off and Loop has never completed", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "حلقة مفتوحة · لم يعمل بعد" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevřená smyčka · zatím neproběhla" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Åbent Loop · ikke kørt endnu" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Open Loop · noch nicht gelaufen" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Circuito abierto · aún no se ha ejecutado" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Avoin säätö · ei vielä ajettu" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Boucle ouverte · pas encore exécuté" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Open Loop · טרם רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nyitott hurok · még nem futott" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Loop aperto · non ancora eseguito" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "オープンループ · 未実行" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Åpen Loop · ikke kjørt ennå" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Open loop · nog niet gedraaid" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Pętla otwarta · jeszcze nie działała" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Ciclo aberto · ainda não executou" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Buclă deschisă · nu a rulat încă" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "г" + "value" : "Открытый цикл · ещё не запускался" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Otvorená slučka · ešte neprebehla" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Öppen loop · inte körd än" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "gr" + "value" : "Açık döngü · henüz çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкритий цикл · ще не запускався" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "g" + "value" : "Vòng lặp mở · chưa chạy" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "克" + "value" : "开环 · 尚未运行" } } } }, - "Glucose level" : { + "Open the app to update the widget" : { + "comment" : "No comment", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Blutzuckerspiegel" + "value" : "Öffne die App, um das Widget zu aktualisieren" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Niveau de glycémie" + "value" : "Ouvrez l'application pour mettre à jour le widget" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "Glukosenivå" + "value" : "Åpne appen for å oppdatere widgeten" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Glucosewaarde" + "value" : "Open de app om de widget bij te werken" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "Nivelul glicemiei" + "value" : "Deschideți aplicația pentru a actualiza widgetul" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "血糖水平" + "value" : "打开应用以更新小部件" } } } }, - "Glucose range" : { + "Pre-meal" : { + "comment" : "Menu item under Presets on the Now screen that turns on the pre-meal target", "localizations" : { - "de" : { + "ar" : { "stringUnit" : { "state" : "translated", - "value" : "Zielbereich" + "value" : "Pre-Meal" } }, - "fr" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "Plage de glycémie" + "value" : "Před jídlem" } }, - "nb" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "Glukoseområde" + "value" : "Før-måltid" } }, - "nl" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "Glucosebereik" + "value" : "Vor dem Essen" } }, - "ro" : { + "es" : { "stringUnit" : { "state" : "translated", - "value" : "Intervalul glicemic" + "value" : "Pre-comida" } }, - "zh-Hans" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "血糖范围" + "value" : "Ennen ateriaa" } - } - } - }, - "Loop Status Widget" : { - "localizations" : { - "da" : { + }, + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Widget til loop-status" + "value" : "Pré-repas" } }, - "de" : { + "he" : { "stringUnit" : { "state" : "translated", - "value" : "Loop Status Widget" + "value" : "Pre-Meal" } }, - "es" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "Widget de Estado de Loop" + "value" : "Pre-Meal" } }, - "fr" : { + "it" : { "stringUnit" : { "state" : "translated", - "value" : "Widget d'état de Loop" + "value" : "Pre-pasto" } }, - "it" : { + "ja" : { "stringUnit" : { "state" : "translated", - "value" : "Widget di stato del ciclo" + "value" : "食前" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "Loop Status Widget" + "value" : "Pre-måltid" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Loop" + "value" : "Voorafgaand aan maaltijd" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Widżet Stanu Pętli" + "value" : "Przed posiłkiem" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pré-refeição" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "Widget de stare Loop" + "value" : "Înainte de masă" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Виджет состояния петли" + "value" : "До еды" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pred jedlom" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Före måltid" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "Döngü Durumu Widget'ı" + "value" : "Yemek öncesi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Перед їжою" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trước bữa ăn" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "Loop 状态小组件" + "value" : "餐前" } } } }, - "mg/dL" : { - "comment" : "The short unit display string for milligrams of glucose per decilter", + "Pre-meal on" : { + "comment" : "Presets button title on the Now screen while the pre-meal target is on", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pre-Meal مفعّل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Před jídlem zapnuto" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Før-måltid til" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Vor dem Essen an" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pre-comida activado" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Ennen ateriaa päällä" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pré-repas activé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal פעיל" } }, - "he" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pre-Meal bekapcsolva" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pre-pasto attivo" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "食前 オン" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pre-måltid på" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Voorafgaand aan maaltijd aan" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dl" + "value" : "Przed posiłkiem wł." } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pré-refeição ligado" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Înainte de masă activ" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "мг/дл" + "value" : "До еды вкл." } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Pred jedlom zapnuté" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dl" + "value" : "Före måltid på" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Yemek öncesi açık" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Перед їжою увімк." } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "Trước bữa ăn đang bật" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "mg/dL" + "value" : "餐前已开启" } } } }, - "mmol/L" : { - "comment" : "The short unit display string for millimoles of glucose per liter", + "Preset override" : { "localizations" : { - "ar" : { - "stringUnit" : { - "state" : "translated", - "value" : "mmol/L" - } - }, - "da" : { - "stringUnit" : { - "state" : "translated", - "value" : "mmol/L" - } - }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Voreinstellung" } }, - "es" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Annulation du préréglage" } }, - "fi" : { + "nb" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Forhåndsinnstilt overstyring" } }, - "fr" : { + "nl" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Override-programma" } }, - "he" : { + "ro" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Suprascriere presetată" } }, - "it" : { + "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "预设覆盖" } - }, - "ja" : { + } + } + }, + "Presets" : { + "comment" : "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item", + "localizations" : { + "ar" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "الإعدادات المسبقة" } }, - "nb" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Předvolby" } }, - "nl" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Forudindstillinger" } }, - "pl" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Voreinstellungen" } }, - "pt-BR" : { + "es" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Ajustes preestablecidos" } }, - "ro" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Esiasetukset" } }, - "ru" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Préréglages" } }, - "sk" : { + "he" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "הגדרות מראש" } }, - "sv" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Előbeállítások" } }, - "tr" : { + "it" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "Preimpostazioni" } }, - "vi" : { + "ja" : { "stringUnit" : { "state" : "translated", - "value" : "mmol/L" + "value" : "プリセット" } }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "mmol/L" - } - } - } - }, - "Open the app to update the widget" : { - "comment" : "No comment", - "localizations" : { - "de" : { + "nb" : { "stringUnit" : { "state" : "translated", - "value" : "Öffne die App, um das Widget zu aktualisieren" + "value" : "Forhåndsinnstillinger" } }, - "fr" : { + "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Ouvrez l'application pour mettre à jour le widget" + "value" : "Programma's" } }, - "nb" : { + "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Åpne appen for å oppdatere widgeten" + "value" : "Ustawienia wstępne" } }, - "nl" : { + "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "Open de app om de widget bij te werken" + "value" : "Predefinições" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "Deschideți aplicația pentru a actualiza widgetul" + "value" : "Presetări" } }, - "zh-Hans" : { + "ru" : { "stringUnit" : { "state" : "translated", - "value" : "打开应用以更新小部件" + "value" : "Пресеты" } - } - } - }, - "Preset override" : { - "localizations" : { - "de" : { + }, + "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Voreinstellung" + "value" : "Predvoľby" } }, - "fr" : { + "sv" : { "stringUnit" : { "state" : "translated", - "value" : "Annulation du préréglage" + "value" : "Förinställningar" } }, - "nb" : { + "tr" : { "stringUnit" : { "state" : "translated", - "value" : "Forhåndsinnstilt overstyring" + "value" : "Ön Ayarlar" } }, - "nl" : { + "uk" : { "stringUnit" : { "state" : "translated", - "value" : "Override-programma" + "value" : "Пресети" } }, - "ro" : { + "vi" : { "stringUnit" : { "state" : "translated", - "value" : "Suprascriere presetată" + "value" : "Cài đặt sẵn" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "预设覆盖" + "value" : "预设" } } } @@ -1957,6 +5103,149 @@ } } } + }, + "Urgent low" : { + "comment" : "Pill under the glucose value on the Now screen when glucose is below 54 mg/dL (3.0 mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "منخفض عاجل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kriticky nízká" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akut lav" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dringend niedrig" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baja urgente" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vaarallisen matala" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basse urgente" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נמוך דחוף" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sürgősen alacsony" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bassa urgente" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "緊急低値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akutt lav" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Urgent laag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Krytycznie niska" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baixa urgente" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Urgent scăzută" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опасно низкая" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kriticky nízka" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akut lågt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acil düşük" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Небезпечно низька" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thấp khẩn cấp" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "紧急低血糖" + } + } + } } }, "version" : "1.0" diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/accent-ink.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/accent-ink.colorset/Contents.json new file mode 100644 index 0000000000..af109ce19a --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/accent-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.384", + "blue": "0.800", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.039", + "green": "0.518", + "blue": "1.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/accent.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/accent.colorset/Contents.json new file mode 100644 index 0000000000..9b711cb95b --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/accent.colorset/Contents.json @@ -0,0 +1,15 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "ios", + "reference" : "systemBlueColor" + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/agp-inner.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/agp-inner.colorset/Contents.json new file mode 100644 index 0000000000..2ddc0f5f90 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/agp-inner.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.690", + "blue": "1.000", + "alpha": "0.340" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "0.380" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/agp-outer.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/agp-outer.colorset/Contents.json new file mode 100644 index 0000000000..270771d475 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/agp-outer.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.690", + "blue": "1.000", + "alpha": "0.160" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "0.180" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/basal-edge.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/basal-edge.colorset/Contents.json new file mode 100644 index 0000000000..9f06dc63c3 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/basal-edge.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.878", + "green": "0.471", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.624", + "blue": "0.039", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/basal.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/basal.colorset/Contents.json new file mode 100644 index 0000000000..5921aa2401 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/basal.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.851", + "blue": "0.639", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.420", + "green": "0.259", + "blue": "0.063", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/carbs-ink.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/carbs-ink.colorset/Contents.json new file mode 100644 index 0000000000..df21da3860 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/carbs-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.184", + "green": "0.490", + "blue": "0.086", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.349", + "green": "0.894", + "blue": "0.200", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/carbs.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/carbs.colorset/Contents.json new file mode 100644 index 0000000000..5d023a96b0 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/carbs.colorset/Contents.json @@ -0,0 +1,68 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.220", + "green" : "0.855", + "red" : "0.388" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.200", + "green" : "0.894", + "red" : "0.349" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "contrast", + "value" : "high" + } + ], + "color" : { + "platform" : "ios", + "reference" : "systemGreenColor" + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + }, + { + "appearance" : "contrast", + "value" : "high" + } + ], + "color" : { + "platform" : "ios", + "reference" : "systemGreenColor" + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/control-thumb.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/control-thumb.colorset/Contents.json new file mode 100644 index 0000000000..34b15edebe --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/control-thumb.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "1.000", + "blue": "1.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.388", + "blue": "0.400", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/critical-ink.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/critical-ink.colorset/Contents.json new file mode 100644 index 0000000000..2f18c32cc1 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/critical-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.769", + "green": "0.188", + "blue": "0.169", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.412", + "blue": "0.380", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/glucose-ink.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/glucose-ink.colorset/Contents.json new file mode 100644 index 0000000000..b704d8af81 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/glucose-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.439", + "blue": "0.722", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/ink-muted.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/ink-muted.colorset/Contents.json new file mode 100644 index 0000000000..6eda3190f3 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/ink-muted.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.424", + "green": "0.424", + "blue": "0.439", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.682", + "green": "0.682", + "blue": "0.698", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/insulin-ink.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/insulin-ink.colorset/Contents.json new file mode 100644 index 0000000000..d9eb09683b --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/insulin-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.639", + "green": "0.322", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.624", + "blue": "0.039", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/range-high.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-high.colorset/Contents.json new file mode 100644 index 0000000000..28f578bf71 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-high.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.949", + "green": "0.718", + "blue": "0.020", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.839", + "blue": "0.039", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/range-in.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-in.colorset/Contents.json new file mode 100644 index 0000000000..3d0f452a75 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-in.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.184", + "green": "0.659", + "blue": "0.310", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.196", + "green": "0.843", + "blue": "0.294", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/range-low.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-low.colorset/Contents.json new file mode 100644 index 0000000000..1349d6a59e --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-low.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.898", + "green": "0.282", + "blue": "0.302", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.624", + "blue": "0.604", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/range-very-high.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-very-high.colorset/Contents.json new file mode 100644 index 0000000000..b2851438d1 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-very-high.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.541", + "green": "0.380", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.788", + "green": "0.541", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/range-very-low.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-very-low.colorset/Contents.json new file mode 100644 index 0000000000..46e9e70555 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/range-very-low.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.608", + "green": "0.110", + "blue": "0.122", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.271", + "blue": "0.227", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/status-critical.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/status-critical.colorset/Contents.json new file mode 100644 index 0000000000..9c67fd2db6 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/status-critical.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.231", + "blue": "0.188", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.271", + "blue": "0.227", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/DerivedAssetsBase.xcassets/target-band.colorset/Contents.json b/Loop Widget Extension/DerivedAssetsBase.xcassets/target-band.colorset/Contents.json new file mode 100644 index 0000000000..6ff45863c5 --- /dev/null +++ b/Loop Widget Extension/DerivedAssetsBase.xcassets/target-band.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.690", + "blue": "1.000", + "alpha": "0.140" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "0.180" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop Widget Extension/Live Activity/GlucoseLiveActivityConfiguration.swift b/Loop Widget Extension/Live Activity/GlucoseLiveActivityConfiguration.swift index b288c71458..2a7d8f1bd4 100644 --- a/Loop Widget Extension/Live Activity/GlucoseLiveActivityConfiguration.swift +++ b/Loop Widget Extension/Live Activity/GlucoseLiveActivityConfiguration.swift @@ -45,6 +45,8 @@ struct GlucoseLiveActivityConfiguration: Widget { // banner on the Home Screen of devices that don't support the Dynamic Island. if #available(iOS 18.0, *) { AdaptiveLockScreenView(context: context) + } else if WidgetDesign.useRedesign { + RedesignLiveActivity.lockScreen(context) } else { fullLockScreenView(context: context) } @@ -56,7 +58,13 @@ struct GlucoseLiveActivityConfiguration: Widget { @Environment(\.activityFamily) private var activityFamily var body: some View { - if activityFamily == .small { + if WidgetDesign.useRedesign { + if activityFamily == .small { + RedesignLiveActivity.smallFamily(context) + } else { + RedesignLiveActivity.lockScreen(context) + } + } else if activityFamily == .small { // WatchOS & CarPlay supplemental view - show only bottom row compactLockScreenView(context: context) } else { @@ -261,6 +269,9 @@ struct GlucoseLiveActivityConfiguration: Widget { private func dynamicIslandView( context: ActivityViewContext ) -> DynamicIsland { + if WidgetDesign.useRedesign { + return RedesignLiveActivity.dynamicIsland(context) + } let glucoseFormatter = NumberFormatter.glucoseFormatter( for: context.state.isMmol ? HKUnit.millimolesPerLiter : HKUnit.milligramsPerDeciliter diff --git a/Loop Widget Extension/Redesign/RedesignLiveActivity.swift b/Loop Widget Extension/Redesign/RedesignLiveActivity.swift new file mode 100644 index 0000000000..c976fac5a7 --- /dev/null +++ b/Loop Widget Extension/Redesign/RedesignLiveActivity.swift @@ -0,0 +1,372 @@ +// +// RedesignLiveActivity.swift +// Loop Widget Extension +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import ActivityKit +import Charts +import HealthKit +import LoopCore +import LoopKit +import SwiftUI +import WidgetKit + +/// The Live Activity in the redesign's style. It reads the same `GlucoseActivityAttributes` as the +/// classic one, so the Live Activity settings (chart, bottom row, limits) keep working. +@available(iOS 16.2, *) +enum RedesignLiveActivity { + typealias Context = ActivityViewContext + private typealias P = LoopDesign.Palette + + // MARK: - Shared pieces + + private static func unitName(_ context: Context) -> String { + (context.state.isMmol ? HKUnit.millimolesPerLiter : HKUnit.milligramsPerDeciliter).localizedShortUnitString + } + + private static func format(_ value: Double, _ context: Context) -> String { + NumberFormatter.glucoseFormatter(for: context.state.isMmol ? .millimolesPerLiter : .milligramsPerDeciliter).string(from: value) ?? "–" + } + + static func range(_ context: Context) -> WidgetDesign.Range? { + WidgetDesign.Range(context.state.currentGlucose, isMmol: context.state.isMmol) + } + + static func status(_ context: Context) -> WidgetDesign.LoopStatus { + WidgetDesign.LoopStatus(closedLoop: context.state.isCloseLoop, lastCompleted: context.state.lastCompleted) + } + + /// Low and high in words, otherwise the unit and the change, as under the Now screen's number. + @ViewBuilder + private static func detail(_ context: Context) -> some View { + if let range = range(context) { + HStack(spacing: LoopDesign.Space.s1) { + Circle().fill(range.color).frame(width: 7, height: 7) + Text(range.text) + } + .font(.caption.weight(.semibold)) + .foregroundStyle(P.ink) + } else { + Text(WidgetDesign.readingDetail(unit: unitName(context), delta: context.state.delta)) + .font(.caption) + .foregroundStyle(P.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.8) + } + } + + private static func eventually(_ context: Context) -> String? { + context.state.eventualGlucose.map { + String(format: NSLocalizedString("Eventually %1$@ %2$@", comment: "Header detail of the Next 3 hours card on the Now screen: the glucose Loop predicts at the end of its prediction. (1: glucose value; 2: glucose unit)"), format($0, context), unitName(context)) + } + } + + private static func hero(_ context: Context, size: CGFloat) -> some View { + VStack(alignment: .leading, spacing: 0) { + WidgetGlucoseValue(value: format(context.state.currentGlucose, context), trend: context.state.trendType, size: size) + detail(context) + } + } + + // MARK: - Lock Screen + + static func lockScreen(_ context: Context) -> some View { + VStack(alignment: .leading, spacing: LoopDesign.Space.s1) { + HStack(alignment: .top) { + hero(context, size: context.attributes.mode == .large ? 30 : 38) + Spacer(minLength: LoopDesign.Space.s2) + VStack(alignment: .trailing, spacing: 4) { + WidgetStatusLine(status: status(context)) + if let eventually = eventually(context) { + Text(eventually) + .font(.caption) + .foregroundStyle(P.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.8) + } + } + } + if context.attributes.mode == .large { + RedesignActivityChart(context: context) + .frame(height: 54) + } + let tiles = tileItems(context) + if !tiles.isEmpty { + HStack(spacing: 6) { + ForEach(tiles, id: \.self) { item in + tile(item, context, inline: context.attributes.mode == .large) + } + } + .padding(.top, 2) + } + } + .padding(.horizontal, 14) + .padding(.vertical, 10) + .overlay { + if context.state.ended { + Text(NSLocalizedString("Open the app to update the widget", comment: "No comment")) + .font(.subheadline.weight(.semibold)) + .foregroundStyle(P.ink) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.ultraThinMaterial) + } + } + .privacySensitive() + .activityBackgroundTint(P.surfaceRaised.opacity(0.92)) + .activitySystemActionForegroundColor(P.ink) + } + + /// The watch and CarPlay size: the number, the change and the prediction. + static func smallFamily(_ context: Context) -> some View { + HStack(alignment: .center) { + hero(context, size: 26) + Spacer(minLength: LoopDesign.Space.s1) + VStack(alignment: .trailing, spacing: 2) { + Circle().fill(status(context).color).frame(width: 8, height: 8) + if let eventual = context.state.eventualGlucose { + Text(format(eventual, context)) + .font(.system(.headline, design: .rounded).weight(.semibold).monospacedDigit()) + .foregroundStyle(P.ink) + Text(NSLocalizedString("Eventually", comment: "Short label above the glucose Loop predicts at the end of its prediction, in a small tile on the widget and Live Activity. Keep it to one short word, such as 'Forecast'.")) + .font(.caption2) + .foregroundStyle(P.inkMuted) + } + } + } + .padding(LoopDesign.Space.s3) + .privacySensitive() + } + + /// The configured bottom row, less the reading and its change, which the hero already shows. + private static func tileItems(_ context: Context) -> [BottomRowItem] { + context.state.bottomRow.filter { item in + switch item.type { + case .currentBg: return false + case .generic: return item.value != context.state.delta || item.unit != "" + case .basal: return true + } + } + } + + @ViewBuilder + private static func tile(_ item: BottomRowItem, _ context: Context, inline: Bool) -> some View { + switch item.type { + case .basal: + WidgetTile(label: NSLocalizedString("Basal", comment: "Label of a tile showing the current basal rate (Now screen) or the day's basal insulin total (Today so far totals)"), inline: inline) { + Text(String(format: NSLocalizedString("%1$@ U/h", comment: "Insulin rate in units per hour. (1: number)"), WidgetDesign.signed(item.rate, decimals: 2))) + .foregroundStyle(P.insulinInk) + } + case .generic, .currentBg: + WidgetTile(label: item.label, inline: inline) { + switch item.unit { + case "U": + Text(String(format: NSLocalizedString("%1$@ U", comment: "Insulin amount in units. (1: number)"), item.value)) + .foregroundStyle(P.insulinInk) + case "g": + Text(String(format: NSLocalizedString("%1$@ g", comment: "Amount of carbohydrate in grams. (1: number)"), item.value)) + .foregroundStyle(P.carbsInk) + default: + Text(item.value) + .foregroundStyle(P.ink) + } + } + } + } + + // MARK: - Dynamic Island + + static func dynamicIsland(_ context: Context) -> DynamicIsland { + DynamicIsland { + DynamicIslandExpandedRegion(.leading) { + hero(context, size: 34) + .padding(.leading, LoopDesign.Space.s1) + .dynamicIsland(verticalPlacement: .belowIfTooWide) + } + // The trailing region is narrow, so it holds only the prediction, labelled like the widget's tile; + // Loop's status gets the full width above the chart, where long translations still fit. + DynamicIslandExpandedRegion(.trailing) { + if let eventual = context.state.eventualGlucose { + VStack(alignment: .trailing, spacing: 0) { + Text(NSLocalizedString("Eventually", comment: "Short label above the glucose Loop predicts at the end of its prediction, in a small tile on the widget and Live Activity. Keep it to one short word, such as 'Forecast'.")) + .font(.caption2) + .foregroundStyle(P.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.7) + Text(format(eventual, context)) + .font(.system(.title3, design: .rounded).weight(.semibold).monospacedDigit()) + .foregroundStyle(P.ink) + } + .padding(.trailing, LoopDesign.Space.s1) + .padding(.top, LoopDesign.Space.s1) + } + } + DynamicIslandExpandedRegion(.bottom) { + VStack(alignment: .leading, spacing: LoopDesign.Space.s1) { + WidgetStatusLine(status: status(context), font: .caption.weight(.medium)) + RedesignActivityChart(context: context) + .frame(height: 46) + } + .padding(.horizontal, LoopDesign.Space.s1) + } + } compactLeading: { + HStack(spacing: 3) { + Text(format(context.state.currentGlucose, context)) + .font(.system(.body, design: .rounded).weight(.semibold).monospacedDigit()) + .foregroundStyle(.white) + .minimumScaleFactor(0.6) + if let trend = context.state.trendType { + Image(systemName: WidgetDesign.trendSymbol(trend)) + .font(.system(size: 11, weight: .bold)) + .foregroundStyle(P.glucose) + } + } + } compactTrailing: { + HStack(spacing: 4) { + if let range = range(context) { + Text(range.text) + .font(.caption.weight(.semibold)) + .foregroundStyle(range.color) + } else { + Text(context.state.delta) + .font(.system(.caption, design: .rounded).weight(.medium).monospacedDigit()) + .foregroundStyle(Color(white: 0.75)) + } + Circle().fill(status(context).color).frame(width: 6, height: 6) + } + .minimumScaleFactor(0.6) + } minimal: { + Text(format(context.state.currentGlucose, context)) + .font(.system(.caption, design: .rounded).weight(.semibold).monospacedDigit()) + .foregroundStyle(.white) + .minimumScaleFactor(0.5) + } + // The island's outline says low or high, so the number itself stays white. + .keylineTint(range(context)?.color ?? P.glucose) + } +} + +// MARK: - Chart + +/// The Now screen's prediction chart, sized for the Live Activity: blue readings, Loop's dashed +/// prediction and the target band. +@available(iOS 16.2, *) +struct RedesignActivityChart: View { + let context: ActivityViewContext + private typealias P = LoopDesign.Palette + + private var lowerLimit: Double { + context.state.isMmol ? context.attributes.lowerLimitChartMmol : context.attributes.lowerLimitChartMg + } + + private var upperLimit: Double { + context.state.isMmol ? context.attributes.upperLimitChartMmol : context.attributes.upperLimitChartMg + } + + /// With "use limits" on, readings outside them take the Trends range colours; the rest stay blue. + private func color(_ value: Double) -> Color { + guard context.attributes.useLimits else { return P.glucose } + if value < lowerLimit { return P.rangeLow } + if value > upperLimit { return P.rangeHigh } + return P.glucose + } + + private var prediction: [(Date, Double)] { + guard context.attributes.addPredictiveLine, let start = context.state.predicatedStartDate else { return [] } + let interval = context.state.predicatedInterval ?? .minutes(5) + let end = start.addingTimeInterval(.hours(3)) + return context.state.predicatedGlucose.enumerated() + .map { (start.addingTimeInterval(interval * Double($0.offset)), $0.element) } + .filter { $0.0 <= end } + } + + private var domain: ClosedRange { + let marks = context.state.yAxisMarks + return (marks.first ?? 0)...(marks.last ?? 1) + } + + private func clamp(_ value: Double) -> Double { + min(max(value, domain.lowerBound), domain.upperBound) + } + + /// The readings Loop sent and its prediction, at least an hour ahead, as on the Now screen's chart. + private var window: ClosedRange { + let now = context.state.date + let start = min(context.state.glucoseSamples.first?.x ?? now.addingTimeInterval(.hours(-3)), now.addingTimeInterval(.hours(-1))) + let end = max(prediction.last?.0 ?? now, now.addingTimeInterval(.hours(1))) + return start...end + } + + var body: some View { + Chart { + ForEach(context.state.glucoseRanges.filter { $0.endDate > window.lowerBound && $0.startDate < window.upperBound }) { band in + RectangleMark(xStart: .value("Start", max(band.startDate, window.lowerBound)), xEnd: .value("End", min(band.endDate, window.upperBound)), + yStart: .value("Low", clamp(band.minValue)), yEnd: .value("High", clamp(max(band.maxValue, band.minValue + domainPadding)))) + .foregroundStyle(band.isOverride ? P.accent.opacity(0.25) : P.targetBand) + } + ForEach(Array(context.state.glucoseSamples.enumerated()), id: \.offset) { _, sample in + PointMark(x: .value("Time", sample.x), y: .value("Glucose", clamp(sample.y))) + .symbolSize(9) + .foregroundStyle(color(sample.y)) + } + ForEach(Array(prediction.enumerated()), id: \.offset) { _, point in + LineMark(x: .value("Time", point.0), y: .value("Predicted", clamp(point.1)), series: .value("Series", "prediction")) + .foregroundStyle(P.glucose) + .lineStyle(StrokeStyle(lineWidth: 1.5, dash: [4, 3])) + } + RuleMark(x: .value("Now", context.state.date)) + .foregroundStyle(P.inkMuted) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [2, 3])) + } + .chartXScale(domain: window) + .chartYScale(domain: domain) + .chartYAxis { + AxisMarks(position: .leading, values: axisLabels) { _ in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel().font(LoopDesign.Typeface.caption).foregroundStyle(P.inkMuted) + } + } + .chartXAxis { + AxisMarks(values: hourMarks) { _ in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel(format: .dateTime.hour()).font(LoopDesign.Typeface.caption).foregroundStyle(P.inkMuted) + } + } + .chartLegend(.hidden) + .overlay(alignment: .topTrailing) { + if let preset = context.state.preset, preset.endDate > context.state.date { + Text(preset.title) + .font(.caption2.weight(.semibold)) + .foregroundStyle(P.ink) + .padding(.horizontal, 6) + .padding(.vertical, 2) + .background(P.accent.opacity(0.25), in: Capsule()) + } + } + .accessibilityHidden(true) + } + + /// Whole hours inside the window, kept clear of the edges so their labels aren't clipped. + private var hourMarks: [Date] { + let calendar = Calendar.current + guard var hour = calendar.dateInterval(of: .hour, for: window.lowerBound)?.end else { return [] } + var marks: [Date] = [] + while hour <= window.upperBound.addingTimeInterval(.minutes(-25)) { + if hour >= window.lowerBound.addingTimeInterval(.minutes(12)) { marks.append(hour) } + hour = hour.addingTimeInterval(.hours(1)) + } + return marks + } + + /// Every other value Loop suggests, so labels don't crowd a chart this short. + private var axisLabels: [Double] { + let marks = context.state.yAxisMarks + return marks.count > 3 ? marks.enumerated().filter { $0.offset % 2 == 0 }.map(\.element) : marks + } + + /// A single-value target is drawn as a thin band, so it stays visible. + private var domainPadding: Double { + (domain.upperBound - domain.lowerBound) / 60 + } +} diff --git a/Loop Widget Extension/Redesign/RedesignStatusWidgetView.swift b/Loop Widget Extension/Redesign/RedesignStatusWidgetView.swift new file mode 100644 index 0000000000..442acb0a9b --- /dev/null +++ b/Loop Widget Extension/Redesign/RedesignStatusWidgetView.swift @@ -0,0 +1,172 @@ +// +// RedesignStatusWidgetView.swift +// Loop Widget Extension +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import HealthKit +import LoopCore +import LoopKit +import SwiftUI +import WidgetKit + +/// The home screen widget in the redesign's style: the Now screen's hero on the left, and in the medium +/// size the Now screen's actions on the right. +struct RedesignStatusWidgetView: View { + @Environment(\.widgetFamily) private var family + @Environment(\.widgetRenderingMode) private var renderingMode + + let entry: StatusWidgetTimelimeEntry + + private typealias P = LoopDesign.Palette + + var body: some View { + HStack(spacing: LoopDesign.Space.s3) { + status + if family != .systemSmall { + actions + } + } + .padding(LoopDesign.Space.s3) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .redesignWidgetBackground(renderingMode == .accented ? .clear : P.surfaceRaised) + } + + // MARK: - Status + + private var status: some View { + VStack(alignment: .leading, spacing: 0) { + WidgetStatusLine(status: WidgetDesign.LoopStatus(closedLoop: entry.closeLoop, lastCompleted: entry.lastLoopCompleted, now: entry.date)) + .opacity(entry.contextIsStale ? 0.6 : 1) + Spacer(minLength: LoopDesign.Space.s1) + reading + Spacer(minLength: LoopDesign.Space.s2) + footer + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) + } + + @ViewBuilder + private var reading: some View { + if let glucose = entry.currentGlucose, let unit = entry.unit, !entry.glucoseIsStale { + let value = glucose.quantity.doubleValue(for: unit) + VStack(alignment: .leading, spacing: 0) { + WidgetGlucoseValue( + value: NumberFormatter.glucoseFormatter(for: unit).string(from: value) ?? "–", + trend: entry.sensor?.trendType, + size: 40 + ) + if let range = WidgetDesign.Range(mgdl: glucose.quantity.doubleValue(for: .milligramsPerDeciliter)) { + HStack(spacing: LoopDesign.Space.s1) { + Circle().fill(range.color).frame(width: 7, height: 7) + Text(range.text) + } + .font(.caption.weight(.semibold)) + .foregroundStyle(P.ink) + } else { + Text(WidgetDesign.readingDetail(unit: unit.localizedShortUnitString, delta: delta(in: unit))) + .font(.caption) + .foregroundStyle(P.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.8) + } + } + .opacity(entry.glucoseStatusIsStale ? 0.6 : 1) + } else { + VStack(alignment: .leading, spacing: 2) { + Text(NSLocalizedString("No reading", comment: "Shown on the Now screen in place of the glucose value when there is no recent CGM reading")) + .font(.system(size: 22, weight: .bold, design: .rounded)) + .foregroundStyle(P.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.7) + if let date = entry.currentGlucose?.startDate { + Text(String(format: NSLocalizedString("Last reading %1$@ ago", comment: "Shown on the Now screen under No reading when the latest CGM reading is too old. (1: duration, e.g. 25m)"), WidgetDesign.duration(entry.date.timeIntervalSince(date)))) + .font(.caption) + .foregroundStyle(P.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.8) + } + } + } + } + + private func delta(in unit: HKUnit) -> String? { + guard let delta = entry.delta else { return nil } + return WidgetDesign.signed(delta.doubleValue(for: unit), decimals: unit == .millimolesPerLiter ? 1 : 0) + } + + /// A device problem replaces the tiles, as notices lead the Now screen. + @ViewBuilder + private var footer: some View { + if let notice = WidgetNotice.mostSerious([entry.pumpHighlight, entry.cgmHighlight]) { + notice + } else { + HStack(spacing: 6) { + WidgetTile(label: NSLocalizedString("COB", comment: "Abbreviation for carbs on board; label of a tile on the Now screen")) { + Text(entry.carbsOnBoard.map { String(format: NSLocalizedString("%1$@ g", comment: "Amount of carbohydrate in grams. (1: number)"), Self.number($0, decimals: 0)) } ?? "–") + .foregroundStyle(P.carbsInk) + } + WidgetTile(label: NSLocalizedString("Eventually", comment: "Short label above the glucose Loop predicts at the end of its prediction, in a small tile on the widget and Live Activity. Keep it to one short word, such as 'Forecast'.")) { + Text(eventual ?? "–") + .foregroundStyle(P.ink) + } + } + .opacity(entry.contextIsStale ? 0.6 : 1) + } + } + + private var eventual: String? { + guard let eventual = entry.eventualGlucose else { return nil } + return NumberFormatter.glucoseFormatter(for: eventual.unit).string(from: eventual.quantity.doubleValue(for: eventual.unit)) + } + + static func number(_ value: Double, decimals: Int) -> String { + value.formatted(.number.precision(.fractionLength(decimals))) + } + + // MARK: - Actions + + private var actions: some View { + VStack(spacing: 6) { + HStack(spacing: 6) { + action(.carbEntry, NSLocalizedString("Add carbs", comment: "Button on the Now screen that opens carb entry"), "fork.knife", fill: P.carbs, ink: P.onFill) + action(.bolus, NSLocalizedString("Bolus", comment: "Button on the Now screen that opens the bolus screen"), "syringe.fill", fill: P.insulin, ink: P.onFill) + } + HStack(spacing: 6) { + if entry.preMealPresetAllowed { + action(.preMeal, + entry.preMealPresetActive + ? NSLocalizedString("Pre-meal on", comment: "Presets button title on the Now screen while the pre-meal target is on") + : NSLocalizedString("Pre-meal", comment: "Menu item under Presets on the Now screen that turns on the pre-meal target"), + "fork.knife.circle", + fill: entry.preMealPresetActive ? P.accent.opacity(0.18) : WidgetDesign.sunken, ink: P.ink) + } + action(.customPreset, NSLocalizedString("Presets", comment: "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item"), "slider.horizontal.3", + fill: entry.customPresetActive ? P.accent.opacity(0.18) : WidgetDesign.sunken, ink: P.ink) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + + private func action(_ destination: SystemActionLink.Destination, _ title: String, _ symbol: String, fill: Color, ink: Color) -> some View { + Link(destination: destination.deeplink) { + VStack(alignment: .leading, spacing: 2) { + Image(systemName: symbol) + .font(.system(size: 15, weight: .semibold)) + Spacer(minLength: 0) + Text(title) + .font(.footnote.weight(.semibold)) + .lineLimit(2) + .minimumScaleFactor(0.7) + } + .foregroundStyle(renderingMode == .accented ? P.ink : ink) + .padding(LoopDesign.Space.s2) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) + .background( + renderingMode == .accented ? AnyShapeStyle(.white.opacity(0.12)) : AnyShapeStyle(fill), + in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md, style: .continuous) + ) + } + } +} diff --git a/Loop Widget Extension/Redesign/WidgetDesign.swift b/Loop Widget Extension/Redesign/WidgetDesign.swift new file mode 100644 index 0000000000..1dd3fd4b40 --- /dev/null +++ b/Loop Widget Extension/Redesign/WidgetDesign.swift @@ -0,0 +1,250 @@ +// +// WidgetDesign.swift +// Loop Widget Extension +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import HealthKit +import LoopCore +import LoopKit +import SwiftUI + +/// The redesign's rules for the widget and Live Activity, so they read like the Now screen: the glucose +/// number is never tinted, low and high are said in words, and Loop's state is a dot with words. +enum WidgetDesign { + /// The tile fill. The app's sunken grey disappears against a dark home screen widget, so the + /// widget uses a translucent ink that reads on both light and dark. + static let sunken = LoopDesign.Palette.ink.opacity(0.08) + + /// Matches the app's interface setting, which the app mirrors into the app group. + static var useRedesign: Bool { UserDefaults.appGroup?.redesignEnabled ?? true } + + static func trendSymbol(_ trend: GlucoseTrend) -> String { + switch trend { + case .upUpUp: return "arrow.up.to.line" + case .upUp: return "chevron.up.2" + case .up: return "arrow.up" + case .flat: return "arrow.right" + case .down: return "arrow.down" + case .downDown: return "chevron.down.2" + case .downDownDown: return "arrow.down.to.line" + } + } + + enum Range { + case urgentLow, low, high + + /// The Now screen's thresholds: below 54 and 70 mg/dL, above 250 mg/dL. + init?(mgdl: Double) { + switch mgdl { + case ..<54: self = .urgentLow + case ..<70: self = .low + case 250.0.nextUp...: self = .high + default: return nil + } + } + + init?(_ value: Double, isMmol: Bool) { + let unit: HKUnit = isMmol ? .millimolesPerLiter : .milligramsPerDeciliter + self.init(mgdl: HKQuantity(unit: unit, doubleValue: value).doubleValue(for: .milligramsPerDeciliter)) + } + + var text: String { + switch self { + case .urgentLow: return NSLocalizedString("Urgent low", comment: "Pill under the glucose value on the Now screen when glucose is below 54 mg/dL (3.0 mmol/L)") + case .low: return NSLocalizedString("Low", comment: "Pill under the glucose value on the Now screen when glucose is below 70 mg/dL (3.9 mmol/L)") + case .high: return NSLocalizedString("High", comment: "Pill under the glucose value on the Now screen when glucose is above 250 mg/dL (13.9 mmol/L)") + } + } + + var color: Color { + self == .high ? LoopDesign.Palette.statusWarning : LoopDesign.Palette.statusCritical + } + } + + /// Loop's state as on the Now pill. The time of the last run stands in for the Now screen's age, + /// because a widget isn't redrawn every minute and an age would go stale on screen. + struct LoopStatus { + let text: String + let color: Color + + init(closedLoop: Bool, lastCompleted: Date?, now: Date = Date()) { + typealias P = LoopDesign.Palette + guard let lastCompleted else { + text = closedLoop + ? NSLocalizedString("Closed loop · not run yet", comment: "Status pill on the Now screen when closed loop is on but Loop hasn't completed a run yet") + : NSLocalizedString("Open loop · not run yet", comment: "Status pill on the Now screen when closed loop is off and Loop hasn't completed a run yet") + color = P.inkMuted + return + } + let age = max(0, now.timeIntervalSince(lastCompleted)) + if LoopCompletionFreshness(age: age) == .stale { + text = String(format: NSLocalizedString("Loop hasn't run for %1$@", comment: "Notice title on the Now screen when Loop hasn't completed a run recently. (1: duration, e.g. 25m)"), WidgetDesign.duration(age)) + color = P.statusWarning + return + } + let time = lastCompleted.formatted(date: .omitted, time: .shortened) + if closedLoop { + text = String(format: NSLocalizedString("Closed loop · %1$@", comment: "Status pill on the Now screen: closed loop is on. (1: how long ago Loop last ran, e.g. 2m)"), time) + color = LoopCompletionFreshness(age: age) == .fresh ? P.statusAutomated : P.statusWarning + } else { + text = String(format: NSLocalizedString("Open loop · %1$@", comment: "Status pill on the Now screen: closed loop is off. (1: how long ago Loop last ran, e.g. 2m)"), time) + color = P.inkMuted + } + } + } + + static func duration(_ interval: TimeInterval) -> String { + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .abbreviated + formatter.allowedUnits = interval >= 3600 ? [.hour, .minute] : [.minute] + formatter.maximumUnitCount = 2 + return formatter.string(from: interval) ?? "" + } + + /// "mmol/L · +0.2 in 5 min", as under the number on the Now screen. + static func readingDetail(unit: String, delta: String?) -> String { + guard let delta, !delta.isEmpty else { return unit } + return String(format: NSLocalizedString("%1$@ · %2$@ in 5 min", comment: "Under the glucose value on the Now screen: the glucose unit and how much glucose changed over 5 minutes. (1: glucose unit, e.g. mmol/L; 2: signed change, e.g. +0.3)"), unit, delta) + } + + static func signed(_ value: Double, decimals: Int) -> String { + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + formatter.minimumFractionDigits = decimals + formatter.maximumFractionDigits = decimals + formatter.positivePrefix = formatter.plusSign + return formatter.string(from: NSNumber(value: value)) ?? "" + } +} + +/// The status dot with words, as on the Now screen's first pill. +struct WidgetStatusLine: View { + let status: WidgetDesign.LoopStatus + var font: Font = LoopDesign.Typeface.footnote.weight(.medium) + + var body: some View { + HStack(spacing: LoopDesign.Space.s1) { + Circle().fill(status.color).frame(width: 7, height: 7) + Text(status.text) + .lineLimit(1) + .minimumScaleFactor(0.75) + } + .font(font) + .foregroundStyle(LoopDesign.Palette.ink) + } +} + +/// The glucose number with its trend arrow, in the Now hero's type. +struct WidgetGlucoseValue: View { + let value: String + let trend: GlucoseTrend? + var size: CGFloat + + var body: some View { + HStack(alignment: .center, spacing: size * 0.12) { + Text(value) + .font(.system(size: size, weight: .bold, design: .rounded).monospacedDigit()) + .foregroundStyle(LoopDesign.Palette.ink) + .lineLimit(1) + .minimumScaleFactor(0.6) + .widgetAccentable() + if let trend { + Image(systemName: WidgetDesign.trendSymbol(trend)) + .font(.system(size: size * 0.45, weight: .bold)) + .foregroundStyle(LoopDesign.Palette.glucose) + .accessibilityLabel(trend.localizedDescription) + } + } + } +} + +/// A sunken tile with a label over a value, the widget-sized `ValueTile`. +struct WidgetTile: View { + @Environment(\.widgetRenderingMode) private var renderingMode + let label: String + /// Label and value on one line, where height is short (the Live Activity has 160 points). + var inline = false + @ViewBuilder var value: Value + + var body: some View { + let layout = inline + ? AnyLayout(HStackLayout(alignment: .firstTextBaseline, spacing: LoopDesign.Space.s1)) + : AnyLayout(VStackLayout(alignment: .leading, spacing: 1)) + layout { + Text(label) + .font(.caption2) + .foregroundStyle(LoopDesign.Palette.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.7) + value + .font(.system(.subheadline, design: .rounded).weight(.semibold).monospacedDigit()) + .lineLimit(1) + .minimumScaleFactor(0.6) + } + .padding(.horizontal, LoopDesign.Space.s2) + .padding(.vertical, inline ? 5 : 6) + .frame(maxWidth: .infinity, alignment: .leading) + .background( + renderingMode == .accented ? AnyShapeStyle(.white.opacity(0.12)) : AnyShapeStyle(WidgetDesign.sunken), + in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md, style: .continuous) + ) + .accessibilityElement(children: .combine) + } +} + +/// A device problem said in words, as in the Now screen's notices. +struct WidgetNotice: View { + let message: String + let symbol: String + let state: DeviceStatusHighlightState + + /// Critical first, then warnings, then information such as a sensor warming up. + static func mostSerious(_ highlights: [DeviceStatusHighlightContext?]) -> WidgetNotice? { + let rank: (DeviceStatusHighlightState) -> Int = { $0 == .critical ? 0 : $0 == .warning ? 1 : 2 } + guard let highlight = highlights.compactMap({ $0 }).min(by: { rank($0.state) < rank($1.state) }) else { return nil } + return WidgetNotice(message: highlight.localizedMessage, symbol: highlight.imageName, state: highlight.state) + } + + private var tint: Color { + switch state { + case .critical: return LoopDesign.Palette.statusCritical + case .warning: return LoopDesign.Palette.statusWarning + default: return LoopDesign.Palette.glucose + } + } + + var body: some View { + HStack(alignment: .top, spacing: 6) { + Image(systemName: symbol) + .font(.caption.weight(.bold)) + .foregroundStyle(tint) + Text(message.replacingOccurrences(of: "\n", with: " ")) + .font(.caption.weight(.semibold)) + .foregroundStyle(LoopDesign.Palette.ink) + .lineLimit(2) + .minimumScaleFactor(0.8) + } + .padding(.horizontal, LoopDesign.Space.s2) + .padding(.vertical, 6) + .frame(maxWidth: .infinity, alignment: .leading) + .background( + tint.opacity(0.18), + in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md, style: .continuous) + ) + .accessibilityElement(children: .combine) + } +} + +extension View { + /// The widget's container background, in the colour of a Now screen card. + @ViewBuilder + func redesignWidgetBackground(_ color: Color) -> some View { + if #available(iOSApplicationExtension 17.0, *) { + containerBackground(for: .widget) { color } + } else { + background { color } + } + } +} diff --git a/Loop Widget Extension/Timeline/StatusWidgetTimelimeEntry.swift b/Loop Widget Extension/Timeline/StatusWidgetTimelimeEntry.swift index 45271bbe14..eaf762e999 100644 --- a/Loop Widget Extension/Timeline/StatusWidgetTimelimeEntry.swift +++ b/Loop Widget Extension/Timeline/StatusWidgetTimelimeEntry.swift @@ -26,7 +26,9 @@ struct StatusWidgetTimelimeEntry: TimelineEntry { let sensor: GlucoseDisplayableContext? let pumpHighlight: DeviceStatusHighlightContext? + var cgmHighlight: DeviceStatusHighlightContext? = nil let netBasal: NetBasalContext? + var carbsOnBoard: Double? = nil let eventualGlucose: GlucoseContext? diff --git a/Loop Widget Extension/Timeline/StatusWidgetTimelineProvider.swift b/Loop Widget Extension/Timeline/StatusWidgetTimelineProvider.swift index beb8bd2f70..f42cd0134c 100644 --- a/Loop Widget Extension/Timeline/StatusWidgetTimelineProvider.swift +++ b/Loop Widget Extension/Timeline/StatusWidgetTimelineProvider.swift @@ -165,7 +165,9 @@ class StatusWidgetTimelineProvider: TimelineProvider { unit: unit, sensor: context.glucoseDisplay, pumpHighlight: context.pumpStatusHighlightContext, + cgmHighlight: context.cgmStatusHighlightContext, netBasal: netBasal, + carbsOnBoard: context.carbsOnBoard, eventualGlucose: eventualGlucose, preMealPresetAllowed: preMealPresetAllowed, preMealPresetActive: preMealPresetActive, diff --git a/Loop Widget Extension/Widgets/SystemStatusWidget.swift b/Loop Widget Extension/Widgets/SystemStatusWidget.swift index 015f6c5d50..bdcf3ad2f2 100644 --- a/Loop Widget Extension/Widgets/SystemStatusWidget.swift +++ b/Loop Widget Extension/Widgets/SystemStatusWidget.swift @@ -78,7 +78,11 @@ struct SystemStatusWidget: Widget { var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: StatusWidgetTimelineProvider()) { entry in - SystemStatusWidgetEntryView(entry: entry) + if WidgetDesign.useRedesign { + RedesignStatusWidgetView(entry: entry) + } else { + SystemStatusWidgetEntryView(entry: entry) + } } .configurationDisplayName("Loop Status Widget") .description("See your current blood glucose and insulin delivery.") diff --git a/Loop.xcodeproj/project.pbxproj b/Loop.xcodeproj/project.pbxproj index f9e627120a..51a023cb85 100644 --- a/Loop.xcodeproj/project.pbxproj +++ b/Loop.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + E6E73709263FB037F274B2A0 /* WidgetDesign.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE6FCD6C3CA3B693C8A349B /* WidgetDesign.swift */; }; + 8602ACA648AEEBBD4793ED49 /* RedesignStatusWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E169C989E88148A68A4FEFB6 /* RedesignStatusWidgetView.swift */; }; + FE8902221761558AAEDFFE02 /* RedesignLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9792C496505ED5C2F302AB /* RedesignLiveActivity.swift */; }; + 4CC1A96D0600081991783423 /* LoopDesign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD3DDF41B598A8C4B5CEB92 /* LoopDesign.swift */; }; 1419606428D9550400BA86E0 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 437AFEE6203688CF008C4892 /* LoopKitUI.framework */; }; 1419606928D9554E00BA86E0 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 437AFEE6203688CF008C4892 /* LoopKitUI.framework */; }; 1419606A28D955BC00BA86E0 /* MockKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C101947127DD473C004E7EB8 /* MockKitUI.framework */; }; @@ -589,6 +593,19 @@ E9C58A7F24DB529A00487A17 /* counteraction_effect_falling_glucose.json in Resources */ = {isa = PBXBuildFile; fileRef = E9C58A7A24DB529A00487A17 /* counteraction_effect_falling_glucose.json */; }; E9C58A8024DB529A00487A17 /* insulin_effect.json in Resources */ = {isa = PBXBuildFile; fileRef = E9C58A7B24DB529A00487A17 /* insulin_effect.json */; }; FADE0001000000000000DE02 /* DevelopmentBranchAlerter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FADE0001000000000000DE01 /* DevelopmentBranchAlerter.swift */; }; + 89C0C34F420190E8CC7D03B1 /* DayCharts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F40DE2F3FC02CBA3BE7AF2F /* DayCharts.swift */; }; + 332CC9FC011E78CE5BEA583C /* LoopDesign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD3DDF41B598A8C4B5CEB92 /* LoopDesign.swift */; }; + 0C70F4D862F6D3FDB3D91D87 /* LoopHistoryMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21622B2355AED8F6A12FE17C /* LoopHistoryMath.swift */; }; + 2ADBB92A8ABB74360D18EEFA /* LoopHistoryModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471FFD525A4EB897745608BE /* LoopHistoryModels.swift */; }; + A743DC26D066EE5AC88C2F45 /* LoopHistoryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09448CF97996C40BEDDE6588 /* LoopHistoryProvider.swift */; }; + A1B2C3D4E5F6A7B8C9D0E1F2 /* AppearanceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2E1D0C9B8A7F6E5D4C3B2A1 /* AppearanceSettings.swift */; }; + 6A6C1E1C7A26EC88AFB4FAB1 /* DayDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3A83D311A9ECAE563F74A51 /* DayDetailView.swift */; }; + 23B98F0A53A093412229364D /* LogbookScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEDC42672A7A8C57546EA0C /* LogbookScreen.swift */; }; + 3ED693ACBF8F9E416055BD56 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844BECBB6357021979B9443F /* MainTabBarController.swift */; }; + 7705483CFFCF0B89F8F1A08E /* NowScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0874B7B679DB9CE661CCE152 /* NowScreen.swift */; }; + 591F13AF435B37B4818E2F2B /* TrendsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFDE56977CC73CBDA1170C5 /* TrendsComponents.swift */; }; + 5CD0888FF33D6F844A81E638 /* TrendsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF0FD64B2B3E9C9AA8764684 /* TrendsScreen.swift */; }; + 97CF13197936D2794766C84A /* LoopHistoryMathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42B08644C3031D9E815F9892 /* LoopHistoryMathTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -759,6 +776,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + FDE6FCD6C3CA3B693C8A349B /* WidgetDesign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDesign.swift; sourceTree = ""; }; + E169C989E88148A68A4FEFB6 /* RedesignStatusWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedesignStatusWidgetView.swift; sourceTree = ""; }; + DB9792C496505ED5C2F302AB /* RedesignLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedesignLiveActivity.swift; sourceTree = ""; }; 142CB7582A60BF2E0075748A /* EditMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditMode.swift; sourceTree = ""; }; 142CB75A2A60BFC30075748A /* FavoriteFoodsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FavoriteFoodsView.swift; sourceTree = ""; }; 1452F4A82A851C9400F8B9E4 /* AddEditFavoriteFoodViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditFavoriteFoodViewModel.swift; sourceTree = ""; }; @@ -1413,6 +1433,19 @@ F5E0BDDA27E1D71F0033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; F5E0BDE327E1D7230033557E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; FADE0001000000000000DE01 /* DevelopmentBranchAlerter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevelopmentBranchAlerter.swift; sourceTree = ""; }; + 6F40DE2F3FC02CBA3BE7AF2F /* DayCharts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayCharts.swift; sourceTree = ""; }; + 0BD3DDF41B598A8C4B5CEB92 /* LoopDesign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopDesign.swift; sourceTree = ""; }; + 21622B2355AED8F6A12FE17C /* LoopHistoryMath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopHistoryMath.swift; sourceTree = ""; }; + 471FFD525A4EB897745608BE /* LoopHistoryModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopHistoryModels.swift; sourceTree = ""; }; + 09448CF97996C40BEDDE6588 /* LoopHistoryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopHistoryProvider.swift; sourceTree = ""; }; + F2E1D0C9B8A7F6E5D4C3B2A1 /* AppearanceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettings.swift; sourceTree = ""; }; + E3A83D311A9ECAE563F74A51 /* DayDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayDetailView.swift; sourceTree = ""; }; + 7AEDC42672A7A8C57546EA0C /* LogbookScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogbookScreen.swift; sourceTree = ""; }; + 844BECBB6357021979B9443F /* MainTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; + 0874B7B679DB9CE661CCE152 /* NowScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowScreen.swift; sourceTree = ""; }; + 4BFDE56977CC73CBDA1170C5 /* TrendsComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendsComponents.swift; sourceTree = ""; }; + AF0FD64B2B3E9C9AA8764684 /* TrendsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendsScreen.swift; sourceTree = ""; }; + 42B08644C3031D9E815F9892 /* LoopHistoryMathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopHistoryMathTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1524,9 +1557,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 17D23E8E964F381FCC67C938 /* Redesign */ = { + isa = PBXGroup; + children = ( + FDE6FCD6C3CA3B693C8A349B /* WidgetDesign.swift */, + E169C989E88148A68A4FEFB6 /* RedesignStatusWidgetView.swift */, + DB9792C496505ED5C2F302AB /* RedesignLiveActivity.swift */, + ); + path = Redesign; + sourceTree = ""; + }; 14B1736128AED9EC006CCD7C /* Loop Widget Extension */ = { isa = PBXGroup; children = ( + 17D23E8E964F381FCC67C938 /* Redesign */, 147EFE8D2A8BCC5500272438 /* DefaultAssets.xcassets */, 147EFE8F2A8BCD8000272438 /* DerivedAssets.xcassets */, 147EFE912A8BCD8A00272438 /* DerivedAssetsBase.xcassets */, @@ -1726,6 +1770,7 @@ 43776F8E1B8022E90074EA36 /* Loop */ = { isa = PBXGroup; children = ( + 8574687EF267DC59043C0242 /* Redesign */, C16DA84022E8E104008624C2 /* Plugins */, B66D1F322E6A5D6600471149 /* Localizable.xcstrings */, B66D1F382E6A5D6600471149 /* InfoPlist.xcstrings */, @@ -2443,6 +2488,7 @@ A9E6DFED246A0460005B1A1C /* Models */ = { isa = PBXGroup; children = ( + 42B08644C3031D9E815F9892 /* LoopHistoryMathTests.swift */, A9DFAFB224F0415E00950D1E /* CarbBackfillRequestUserInfoTests.swift */, A963B279252CEBAE0062AA12 /* SetBolusUserInfoTests.swift */, A9DFAFB424F048A000950D1E /* WatchHistoricalCarbsTests.swift */, @@ -2665,6 +2711,25 @@ path = Fixtures; sourceTree = ""; }; + 8574687EF267DC59043C0242 /* Redesign */ = { + isa = PBXGroup; + children = ( + AF0FD64B2B3E9C9AA8764684 /* TrendsScreen.swift */, + 4BFDE56977CC73CBDA1170C5 /* TrendsComponents.swift */, + 0874B7B679DB9CE661CCE152 /* NowScreen.swift */, + 844BECBB6357021979B9443F /* MainTabBarController.swift */, + 7AEDC42672A7A8C57546EA0C /* LogbookScreen.swift */, + F2E1D0C9B8A7F6E5D4C3B2A1 /* AppearanceSettings.swift */, + E3A83D311A9ECAE563F74A51 /* DayDetailView.swift */, + 09448CF97996C40BEDDE6588 /* LoopHistoryProvider.swift */, + 471FFD525A4EB897745608BE /* LoopHistoryModels.swift */, + 21622B2355AED8F6A12FE17C /* LoopHistoryMath.swift */, + 0BD3DDF41B598A8C4B5CEB92 /* LoopDesign.swift */, + 6F40DE2F3FC02CBA3BE7AF2F /* DayCharts.swift */, + ); + path = Redesign; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -3345,6 +3410,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E6E73709263FB037F274B2A0 /* WidgetDesign.swift in Sources */, + 8602ACA648AEEBBD4793ED49 /* RedesignStatusWidgetView.swift in Sources */, + FE8902221761558AAEDFFE02 /* RedesignLiveActivity.swift in Sources */, + 4CC1A96D0600081991783423 /* LoopDesign.swift in Sources */, 14B1738128AEDC70006CCD7C /* StatusExtensionContext.swift in Sources */, 14B1737628AEDC6C006CCD7C /* HKUnit.swift in Sources */, 14B1737728AEDC6C006CCD7C /* NSBundle.swift in Sources */, @@ -3382,6 +3451,18 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5CD0888FF33D6F844A81E638 /* TrendsScreen.swift in Sources */, + 591F13AF435B37B4818E2F2B /* TrendsComponents.swift in Sources */, + 7705483CFFCF0B89F8F1A08E /* NowScreen.swift in Sources */, + 3ED693ACBF8F9E416055BD56 /* MainTabBarController.swift in Sources */, + 23B98F0A53A093412229364D /* LogbookScreen.swift in Sources */, + A1B2C3D4E5F6A7B8C9D0E1F2 /* AppearanceSettings.swift in Sources */, + 6A6C1E1C7A26EC88AFB4FAB1 /* DayDetailView.swift in Sources */, + A743DC26D066EE5AC88C2F45 /* LoopHistoryProvider.swift in Sources */, + 2ADBB92A8ABB74360D18EEFA /* LoopHistoryModels.swift in Sources */, + 0C70F4D862F6D3FDB3D91D87 /* LoopHistoryMath.swift in Sources */, + 332CC9FC011E78CE5BEA583C /* LoopDesign.swift in Sources */, + 89C0C34F420190E8CC7D03B1 /* DayCharts.swift in Sources */, C17824A51E1AD4D100D9D25C /* ManualBolusRecommendation.swift in Sources */, 897A5A9624C2175B00C4E71D /* BolusEntryView.swift in Sources */, 4F70C2131DE90339006380B7 /* StatusExtensionContext.swift in Sources */, @@ -3726,6 +3807,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 97CF13197936D2794766C84A /* LoopHistoryMathTests.swift in Sources */, A9DF02CB24F72B9E00B7C988 /* CriticalEventLogTests.swift in Sources */, 1D80313D24746274002810DF /* AlertStoreTests.swift in Sources */, C1777A6625A125F100595963 /* ManualEntryDoseViewModelTests.swift in Sources */, @@ -4419,6 +4501,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = "$(APPICON_NAME)"; + ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconDayNight AppIconDay AppIconNight"; CODE_SIGN_ENTITLEMENTS = "$(LOOP_ENTITLEMENTS)"; CODE_SIGN_IDENTITY = "$(LOOP_CODE_SIGN_IDENTITY_DEBUG)"; CODE_SIGN_STYLE = "$(LOOP_CODE_SIGN_STYLE)"; @@ -4449,6 +4532,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = "$(APPICON_NAME)"; + ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconDayNight AppIconDay AppIconNight"; CODE_SIGN_ENTITLEMENTS = "$(LOOP_ENTITLEMENTS)"; CODE_SIGN_IDENTITY = "$(LOOP_CODE_SIGN_IDENTITY_RELEASE)"; CODE_SIGN_STYLE = "$(LOOP_CODE_SIGN_STYLE)"; diff --git a/Loop/DefaultAssets.xcassets/AppIconPreviewDay.imageset/AppIconPreviewDay.png b/Loop/DefaultAssets.xcassets/AppIconPreviewDay.imageset/AppIconPreviewDay.png new file mode 100644 index 0000000000..e47fb9b46f Binary files /dev/null and b/Loop/DefaultAssets.xcassets/AppIconPreviewDay.imageset/AppIconPreviewDay.png differ diff --git a/Loop/DefaultAssets.xcassets/AppIconPreviewDay.imageset/Contents.json b/Loop/DefaultAssets.xcassets/AppIconPreviewDay.imageset/Contents.json new file mode 100644 index 0000000000..689ca3fe4d --- /dev/null +++ b/Loop/DefaultAssets.xcassets/AppIconPreviewDay.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images": [ + { + "filename": "AppIconPreviewDay.png", + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DefaultAssets.xcassets/AppIconPreviewDayNight.imageset/AppIconPreviewDayNight.png b/Loop/DefaultAssets.xcassets/AppIconPreviewDayNight.imageset/AppIconPreviewDayNight.png new file mode 100644 index 0000000000..5d9ed19352 Binary files /dev/null and b/Loop/DefaultAssets.xcassets/AppIconPreviewDayNight.imageset/AppIconPreviewDayNight.png differ diff --git a/Loop/DefaultAssets.xcassets/AppIconPreviewDayNight.imageset/Contents.json b/Loop/DefaultAssets.xcassets/AppIconPreviewDayNight.imageset/Contents.json new file mode 100644 index 0000000000..b35f62954c --- /dev/null +++ b/Loop/DefaultAssets.xcassets/AppIconPreviewDayNight.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images": [ + { + "filename": "AppIconPreviewDayNight.png", + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DefaultAssets.xcassets/AppIconPreviewNight.imageset/AppIconPreviewNight.png b/Loop/DefaultAssets.xcassets/AppIconPreviewNight.imageset/AppIconPreviewNight.png new file mode 100644 index 0000000000..019c6d968c Binary files /dev/null and b/Loop/DefaultAssets.xcassets/AppIconPreviewNight.imageset/AppIconPreviewNight.png differ diff --git a/Loop/DefaultAssets.xcassets/AppIconPreviewNight.imageset/Contents.json b/Loop/DefaultAssets.xcassets/AppIconPreviewNight.imageset/Contents.json new file mode 100644 index 0000000000..01fec4c507 --- /dev/null +++ b/Loop/DefaultAssets.xcassets/AppIconPreviewNight.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images": [ + { + "filename": "AppIconPreviewNight.png", + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconDay.appiconset/AppIconDay.png b/Loop/DerivedAssetsBase.xcassets/AppIconDay.appiconset/AppIconDay.png new file mode 100644 index 0000000000..767082980e Binary files /dev/null and b/Loop/DerivedAssetsBase.xcassets/AppIconDay.appiconset/AppIconDay.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconDay.appiconset/Contents.json b/Loop/DerivedAssetsBase.xcassets/AppIconDay.appiconset/Contents.json new file mode 100644 index 0000000000..5e9df36117 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/AppIconDay.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images": [ + { + "filename": "AppIconDay.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/AppIconDayNight-Dark.png b/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/AppIconDayNight-Dark.png new file mode 100644 index 0000000000..47a5dad744 Binary files /dev/null and b/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/AppIconDayNight-Dark.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/AppIconDayNight.png b/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/AppIconDayNight.png new file mode 100644 index 0000000000..767082980e Binary files /dev/null and b/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/AppIconDayNight.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/Contents.json b/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/Contents.json new file mode 100644 index 0000000000..c34d1b8588 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/AppIconDayNight.appiconset/Contents.json @@ -0,0 +1,26 @@ +{ + "images": [ + { + "filename": "AppIconDayNight.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "filename": "AppIconDayNight-Dark.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconNight.appiconset/AppIconNight.png b/Loop/DerivedAssetsBase.xcassets/AppIconNight.appiconset/AppIconNight.png new file mode 100644 index 0000000000..47a5dad744 Binary files /dev/null and b/Loop/DerivedAssetsBase.xcassets/AppIconNight.appiconset/AppIconNight.png differ diff --git a/Loop/DerivedAssetsBase.xcassets/AppIconNight.appiconset/Contents.json b/Loop/DerivedAssetsBase.xcassets/AppIconNight.appiconset/Contents.json new file mode 100644 index 0000000000..a9f66f6697 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/AppIconNight.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images": [ + { + "filename": "AppIconNight.png", + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/accent-ink.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/accent-ink.colorset/Contents.json new file mode 100644 index 0000000000..af109ce19a --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/accent-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.384", + "blue": "0.800", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.039", + "green": "0.518", + "blue": "1.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/agp-inner.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/agp-inner.colorset/Contents.json new file mode 100644 index 0000000000..2ddc0f5f90 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/agp-inner.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.690", + "blue": "1.000", + "alpha": "0.340" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "0.380" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/agp-outer.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/agp-outer.colorset/Contents.json new file mode 100644 index 0000000000..270771d475 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/agp-outer.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.690", + "blue": "1.000", + "alpha": "0.160" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "0.180" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/basal-edge.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/basal-edge.colorset/Contents.json new file mode 100644 index 0000000000..9f06dc63c3 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/basal-edge.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.878", + "green": "0.471", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.624", + "blue": "0.039", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/basal.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/basal.colorset/Contents.json new file mode 100644 index 0000000000..5921aa2401 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/basal.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.851", + "blue": "0.639", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.420", + "green": "0.259", + "blue": "0.063", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/carbs-ink.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/carbs-ink.colorset/Contents.json new file mode 100644 index 0000000000..df21da3860 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/carbs-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.184", + "green": "0.490", + "blue": "0.086", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.349", + "green": "0.894", + "blue": "0.200", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/control-thumb.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/control-thumb.colorset/Contents.json new file mode 100644 index 0000000000..34b15edebe --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/control-thumb.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "1.000", + "blue": "1.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.388", + "blue": "0.400", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/critical-ink.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/critical-ink.colorset/Contents.json new file mode 100644 index 0000000000..2f18c32cc1 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/critical-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.769", + "green": "0.188", + "blue": "0.169", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.412", + "blue": "0.380", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/glucose-ink.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/glucose-ink.colorset/Contents.json new file mode 100644 index 0000000000..b704d8af81 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/glucose-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.439", + "blue": "0.722", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/ink-muted.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/ink-muted.colorset/Contents.json new file mode 100644 index 0000000000..6eda3190f3 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/ink-muted.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.424", + "green": "0.424", + "blue": "0.439", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.682", + "green": "0.682", + "blue": "0.698", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/insulin-ink.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/insulin-ink.colorset/Contents.json new file mode 100644 index 0000000000..d9eb09683b --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/insulin-ink.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.639", + "green": "0.322", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.624", + "blue": "0.039", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/range-high.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/range-high.colorset/Contents.json new file mode 100644 index 0000000000..28f578bf71 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/range-high.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.949", + "green": "0.718", + "blue": "0.020", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.839", + "blue": "0.039", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/range-in.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/range-in.colorset/Contents.json new file mode 100644 index 0000000000..3d0f452a75 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/range-in.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.184", + "green": "0.659", + "blue": "0.310", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.196", + "green": "0.843", + "blue": "0.294", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/range-low.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/range-low.colorset/Contents.json new file mode 100644 index 0000000000..1349d6a59e --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/range-low.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.898", + "green": "0.282", + "blue": "0.302", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.624", + "blue": "0.604", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/range-very-high.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/range-very-high.colorset/Contents.json new file mode 100644 index 0000000000..b2851438d1 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/range-very-high.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.541", + "green": "0.380", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.788", + "green": "0.541", + "blue": "0.000", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/range-very-low.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/range-very-low.colorset/Contents.json new file mode 100644 index 0000000000..46e9e70555 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/range-very-low.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.608", + "green": "0.110", + "blue": "0.122", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.271", + "blue": "0.227", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/status-critical.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/status-critical.colorset/Contents.json new file mode 100644 index 0000000000..9c67fd2db6 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/status-critical.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.231", + "blue": "0.188", + "alpha": "1.000" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "1.000", + "green": "0.271", + "blue": "0.227", + "alpha": "1.000" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/DerivedAssetsBase.xcassets/target-band.colorset/Contents.json b/Loop/DerivedAssetsBase.xcassets/target-band.colorset/Contents.json new file mode 100644 index 0000000000..6ff45863c5 --- /dev/null +++ b/Loop/DerivedAssetsBase.xcassets/target-band.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors": [ + { + "color": { + "color-space": "srgb", + "components": { + "red": "0.000", + "green": "0.690", + "blue": "1.000", + "alpha": "0.140" + } + }, + "idiom": "universal" + }, + { + "appearances": [ + { + "appearance": "luminosity", + "value": "dark" + } + ], + "color": { + "color-space": "srgb", + "components": { + "red": "0.388", + "green": "0.729", + "blue": "1.000", + "alpha": "0.180" + } + }, + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Loop/Localizable.xcstrings b/Loop/Localizable.xcstrings index 738c2b1e6a..0ca8b7ac41 100644 --- a/Loop/Localizable.xcstrings +++ b/Loop/Localizable.xcstrings @@ -504,2682 +504,34341 @@ } } }, - "." : { - "comment" : "Full stop character", + "%1$@ d" : { + "comment" : "Trends period picker, short label for a period of several days, e.g. 7 d. (1: number of days)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ يوم" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ d" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ d" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ T" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ d" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ pv" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "-" + "value" : "%1$@ j" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ ימ׳" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nap" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ g" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@日" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ d" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ d" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ d" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ d" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ z" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ д" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ d" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ d" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@ g" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ д" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ngày" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "." + "value" : "%1$@天" } } } }, - "%@ %@" : { - "comment" : "The format for an active custom preset. (1: preset symbol)(2: preset name)", + "%1$@ entries" : { + "comment" : "Trends Carbs per day tile detail: average number of carb entries per day, a fractional value such as 2.5, so not pluralised. (1: number with one decimal)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ إدخالات" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "záznamů: %1$@" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ registreringer" } }, - "en" : { + "de" : { "stringUnit" : { - "state" : "new", - "value" : "%1$@ %2$@" + "state" : "translated", + "value" : "%1$@ Einträge" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ entradas" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ kirjausta" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ entrées" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ רשומות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ bejegyzés" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ inserimenti" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@件" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ registreringer" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ registraties" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "wpisów: %1$@" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ registros" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "%1$@ intrări" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "записей: %1$@" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "záznamov: %1$@" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ registreringar" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ giriş" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "записів: %1$@" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ lần nhập" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@条" } } } }, - "%@ absorbed" : { - "comment" : "Formats absorbed carb value", + "%1$@ for %2$@" : { + "comment" : "A temp basal: its rate and how long it ran. (1: rate, e.g. 0.50 U/h; 2: duration, e.g. 30m)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%@ استغرق" + "value" : "%1$@ لمدة %2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ po dobu %2$@" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%@ optaget" + "value" : "%1$@ i %2$@" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@ resorbiert" + "value" : "%1$@ für %2$@" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorbido" + "value" : "%1$@ durante %2$@" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ imeytynyt" + "value" : "%1$@ %2$@ ajan" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorbé(s)" + "value" : "%1$@ pendant %2$@" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%@ נספג" + "value" : "%1$@ למשך %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ ideig" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%@ assorbiti" + "value" : "%1$@ per %2$@" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%@ 吸収済" + "value" : "%1$@(%2$@間)" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorbert" + "value" : "%1$@ i %2$@" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ geabsorbeerd" + "value" : "%1$@ gedurende %2$@" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ zaabsorbowane" + "value" : "%1$@ przez %2$@" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorvida" + "value" : "%1$@ por %2$@" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorbiți" + "value" : "%1$@ timp de %2$@" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%@ усвоено" + "value" : "%1$@ на %2$@" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorbované" + "value" : "%1$@ počas %2$@" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%@ absorberat" + "value" : "%1$@ i %2$@" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "Emilen %@" + "value" : "%2$@ boyunca %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ на %2$@" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ được hấp thụ" + "value" : "%1$@ trong %2$@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%@ 已吸收" + "value" : "%1$@,持续%2$@" } } } }, - "%@ remaining" : { - "comment" : "Estimated remaining duration with more than a minute", + "%1$@ for %2$@ (scheduled %3$@)" : { + "comment" : "A temp basal: its rate, how long it ran and the scheduled rate it replaced. (1: rate, e.g. 0.50 U/h; 2: duration, e.g. 30m; 3: scheduled rate number, e.g. 0.80)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ لمدة %2$@ (المجدول %3$@)" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ po dobu %2$@ (dle plánu %3$@)" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%@ tilbage" + "value" : "%1$@ i %2$@ (planlagt %3$@)" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@ verbleiben" + "value" : "%1$@ für %2$@ (geplant %3$@)" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%@ restante" + "value" : "%1$@ durante %2$@ (programada %3$@)" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ jäljellä" + "value" : "%1$@ %2$@ ajan (ohjelmoitu %3$@)" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@ restant" + "value" : "%1$@ pendant %2$@ (programmé %3$@)" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%@ נותרו" + "value" : "%1$@ למשך %2$@ (מתוזמן %3$@)" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ ideig (ütemezett: %3$@)" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%@ rimanenti" + "value" : "%1$@ per %2$@ (programmata %3$@)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@(%2$@間、予定 %3$@)" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@ gjenstår" + "value" : "%1$@ i %2$@ (planlagt %3$@)" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ resterend" + "value" : "%1$@ gedurende %2$@ (gepland %3$@)" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Pozostało %@" + "value" : "%1$@ przez %2$@ (wg planu %3$@)" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ por %2$@ (programada %3$@)" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@ rămase" + "value" : "%1$@ timp de %2$@ (programat %3$@)" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Осталось %@" + "value" : "%1$@ на %2$@ (по плану %3$@)" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ počas %2$@ (podľa plánu %3$@)" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%@ återstår" + "value" : "%1$@ i %2$@ (schemalagd %3$@)" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%@ kaldı" + "value" : "%2$@ boyunca %1$@ (planlanan %3$@)" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ на %2$@ (за планом %3$@)" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ trong %2$@ (theo lịch %3$@)" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "剩余 %@" + "value" : "%1$@,持续%2$@(预设 %3$@)" } } } }, - "%@ U Total" : { - "comment" : "The subtitle format describing total insulin. (1: localized insulin total)", + "%1$@ g" : { + "comment" : "Format string for an amount of carbohydrate in grams. (1: grams)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%@ وحدة بشكل كامل" + "value" : "%1$@ g" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E Total" + "value" : "%1$@ g" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@ IE gesamt" + "value" : "%1$@ g" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U Totales" + "value" : "%1$@ g" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U yhteensä" + "value" : "%1$@ g" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U total" + "value" : "%1$@ g" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U סה״כ" + "value" : "%1$@ g" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ g" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U Totali" + "value" : "%1$@ g" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "計 %@ 単位" + "value" : "%1$@ g" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E Totalt" + "value" : "%1$@ g" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E totaal" + "value" : "%1$@ g" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%@ J łącznie" + "value" : "%1$@ g" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U Total" + "value" : "%1$@ g" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U total" + "value" : "%1$@ g" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%@ всего ед" + "value" : "%1$@ г" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%@ j Celkom" + "value" : "%1$@ g" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%@ E totalt" + "value" : "%1$@ g" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "Toplam %@ Ü" + "value" : "%1$@ gr" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ г" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%@ U Tổng cộng" + "value" : "%1$@ g" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%@ 单位 总量" + "value" : "%1$@ 克" } } } }, - "%@." : { - "comment" : "Appends a full-stop to a statement", - "extractionState" : "manual", + "%1$@ h" : { + "comment" : "Time in range row: average hours a day spent in the band, abbreviated. (1: hours with one decimal)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ س" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ t" } }, - "en" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ Std" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ שע׳" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ óra" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@時間" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%@ ." + "value" : "%1$@ t" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ u" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ godz." } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ ч" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%@ ." + "value" : "%1$@ h" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ h" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ sa" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ год" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ giờ" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%@." + "value" : "%1$@ 小时" } } } }, - "%@%@ was unable to cancel your current temporary basal rate, which is higher than the new Max Basal limit you have set. This may result in higher insulin delivery than desired.\n\nConsider suspending insulin delivery manually and then immediately resuming to enact basal delivery with the new limit in place." : { - "comment" : "Alert text for failing to cancel temp basal (1: reason description, 2: app name)", + "%1$@ mmol/mol" : { + "comment" : "Trends GMI tile detail: the GMI in IFCC units. (1: value)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ mmol/mol" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ mmol/mol" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@ kunne ikke annullere din nuværende midlertidige basalrate, som er højere end den nye Max basalgrænse, du har indstillet. Dette kan resultere i en højere insulintilførsel end ønsket.\n\nOvervej at suspendere insulintilførslen manuelt og derefter straks genoptage den for at iværksætte basaltilførslen med den nye grænse på plads." + "value" : "%1$@ mmol/mol" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@ konnte Deine aktuelle temporäre Basalrate nicht abbrechen, da diese höher ist als die neue maximale Basalrate, die Du festgelegt hast. Dies kann zu einer höheren Insulinabgabe, als erwünscht führen.\n\nErwäge, die Insulinabgabe manuell zu unterbrechen und dann sofort wieder aufzunehmen, um die Basalabgabe mit dem neuen Grenzwert zu initiieren." + "value" : "%1$@ mmol/mol" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ no pudo cancelar su basal temporal actual, que es más alta que el nuevo límite basal máximo que ha establecido. Esto puede resultar en una administración de insulina superior a la deseada. \n\n Considere suspender la administración de insulina manualmente y luego reanudarla de inmediato para activar la administración basal con el nuevo límite establecido." + "value" : "%1$@ mmol/mol" } }, - "fr" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ n'a pas pu annuler votre débit basal temporaire actuel, qui est supérieur à la nouvelle limite basale max que vous avez définie. Cela peut entraîner une administration d'insuline plus élevée que souhaitée. \n\nEnvisagez de suspendre l'administration d'insuline manuellement, puis de reprendre immédiatement l'administration basale avec la nouvelle limite en place." + "value" : "%1$@ mmol/mol" } }, - "it" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@ non sono stati in grado di cancellare la tua attuale basale temporanea, che è più elevata di quella impostata come nuovo limite massimo di basale. Questo potrebbe comportare una maggiore infusione d'insulina di quanto desiderato. \n\nConsidera di sospendere manualmente l'erogazione d'insulina e quindi di riattivarla immediatamente per attivare l'erogazione d'insulina basale con il corretto limite impostato." + "value" : "%1$@ mmol/mol" } }, - "nb" : { + "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ kunne ikke avbryte den nåværende midlertidige basaldosen, som er høyere enn den nye maksimale basalgrensen du har angitt. Dette kan føre til høyere insulintilførsel enn ønsket. \n\n Vurder å avbryte insulintilførselen manuelt og deretter umiddelbart gjenoppta for å innføre basaltilførsel med den nye grensen på plass." + "value" : "%1$@ mmol/mol" } }, - "nl" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "%@%@ kon je huidige tijdelijke basaalstand niet annuleren, die hoger is dan de nieuwe maximale basaallimiet die je hebt ingesteld. Dit kan leiden tot een hogere insulinetoediening dan gewenst. \n\nOverweeg om de insulinetoediening handmatig te onderbreken en dan direct het hervatten van de basaaltoediening uit te laten voeren met de nieuwe geldende limiet." + "value" : "%1$@ mmol/mol" } }, - "pl" : { + "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ nie mógł anulować bieżącej tymczasowej dawki podstawowej, która jest wyższa niż nowy ustawiony limit maksymalnej dawki podstawowej. Może to skutkować wyższym niż pożądane podawaniem insuliny. \n\n Rozważ ręczne wstrzymanie podawania insuliny, a następnie natychmiastowe wznowienie podawania dawki podstawowej z obowiązującym nowym limitem." + "value" : "%1$@ mmol/mol" } }, - "ro" : { + "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ nu a putut anula rata bazală temporară actuală, care este mai mare decât noua limită bazală maximă pe care ați setat-o. Acest lucru poate duce la o administrare de insulină mai mare decât se dorește. \n\nLuați în considerare suspendarea manuală a administrării insulinei și apoi reluarea imediată pentru a pune în aplicare administrarea bazală cu noua limită în vigoare." + "value" : "%1$@ mmol/mol" } }, - "ru" : { + "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@ не смог отменить вашу текущую ВБС, которая превышает установленный вами новый предел максимальной ВБС. Это может привести к большему количеству подаваемого инсулина, чем хотелось бы.\n\nРассмотрите возможность приостановить введение инсулина вручную, а затем немедленно возобновить введение базального инсулина с новым установленным лимитом." + "value" : "%1$@ mmol/mol" } }, - "sk" : { + "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@ nedokázal zrušiť vašu aktuálnu dočasnú bazálnu dávku, ktorá je vyššia ako nový maximálny bazálny limit, ktorý ste nastavili. To môže viesť k vyššiemu dodávaniu inzulínu, ako je požadované.\n\nZvážte ručné pozastavenie podávania inzulínu a následné okamžité obnovenie, aby ste uplatnili novým bazálny limit." + "value" : "%1$@ mmol/mol" } }, - "tr" : { + "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ , ayarladığınız yeni Maks Bazal limitinden daha yüksek olan mevcut geçici bazal oranınızı iptal edemedi. Bu, istenenden daha yüksek insülin iletimi ile sonuçlanabilir. \n\n İnsülin iletimini manuel olarak askıya almayı ve ardından yeni limit geçerliyken bazal iletimi etkinleştirmek için hemen devam etmeyi düşünün." + "value" : "%1$@ mmol/mol" } }, - "zh-Hans" : { + "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%@%@ 无法取消当前的临时基础率,该基础率高于您新设定的最大基础率上限。这可能导致胰岛素输注量高于预期。\n\n建议您手动暂停胰岛素输注,然后立即恢复,以便根据新的上限重新执行基础输注。" + "value" : "%1$@ mmol/mol" } - } - } - }, - "%1@%2@" : { - "comment" : "Adds a full-stop to a statement (1: statement, 2: full stop character)", - "localizations" : { - "de" : { + }, + "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } }, - "en" : { + "ru" : { "stringUnit" : { - "state" : "new", - "value" : "%1$1@%2$2@" + "state" : "translated", + "value" : "%1$@ mmol/mol" } }, - "fr" : { + "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } }, - "he" : { + "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } }, - "nb" : { + "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } }, - "nl" : { + "uk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } }, - "ro" : { + "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$1@%2$2@" + "value" : "%1$@ mmol/mol" } } } }, - "%1$@ – %2$@ %3$@" : { - "comment" : "Format string for glucose target range. (1: Min target)(2: Max target)(3: glucose unit)", - "extractionState" : "manual", + "%1$@ of %2$@" : { + "comment" : "Trends Loop active tile detail: time in closed loop out of the time Loop status is known. (1: duration in closed loop, e.g. 6d 4h, 2: duration covered, e.g. 7d) Trends: how many days of the period are averaged. (1: days averaged, a number; 2: days in the period, e.g. 14 days)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ من %2$@" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ z %2$@" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ af %2$@" } }, - "en" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ von %2$@" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ de %2$@" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ / %2$@" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ sur %2$@" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ מתוך %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ / %2$@" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ su %2$@" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ / %2$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ av %2$@" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ - %2$@ %3$@" + "value" : "%1$@ van %2$@" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ z %2$@" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ de %2$@" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ din %2$@" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ из %2$@" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ z %2$@" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ av %2$@" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ / %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ з %2$@" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ / %2$@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ – %2$@ %3$@" + "value" : "%1$@ / %2$@" } } } }, - "%1$@ %2$@" : { - "comment" : "Format string combining carb entry quantity and absorption time emoji", + "%1$@ U/h" : { + "comment" : "Format string for an insulin rate in units per hour. (1: rate)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ وحدة لكل ساعة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/hod" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ E/t" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ IE/Std" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ U/h" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ U/h" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ U/h" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "U/hr %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/óra" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ U/ora" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ 単位/時" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ E/t" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ E/uur" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ J/h" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ U/h" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@%2$@" + "value" : "%1$@ U/oră" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ Ед/ч" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ J/hod" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ IE/h" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ Ü/Sa" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/год" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@" + "value" : "%1$@ U/giờ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/小时" } } } }, - "%1$@ %2$@/U" : { - "comment" : "Format string for carb ratio average. (1: value)(2: carb unit)", - "extractionState" : "manual", + "%1$@ vs plan" : { + "comment" : "Basal tile on the Now screen: how the current basal rate differs from the scheduled rate. (1: signed difference in U/h, e.g. +0.25)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/وحدة" + "value" : "%1$@ مقارنة بالمجدول" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/E" + "value" : "%1$@ oproti plánu" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/IE" + "value" : "%1$@ ift. plan" } }, - "en" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ ggü. Plan" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ vs. lo programado" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ vs. ohjelmoitu" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ vs prévu" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ לעומת התוכנית" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ a tervhez képest" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ vs programmata" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "予定比 %1$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ /E" + "value" : "%1$@ mot plan" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ /E" + "value" : "%1$@ t.o.v. gepland" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/J" + "value" : "%1$@ wzgl. planu" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ vs. programado" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ față de program" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/ед" + "value" : "%1$@ к плану" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ /j" + "value" : "%1$@ oproti plánu" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/E" + "value" : "%1$@ mot schema" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/Ü" + "value" : "plana göre %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ до плану" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/U" + "value" : "%1$@ so với lịch" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@/单位" + "value" : "较预设 %1$@" } } } }, - "%1$@ + %2$@" : { - "comment" : "Format string combining carb entry time and absorption time\nFormats (1: carb start time) and (2: carb absorption duration)", + "%1$@ · %2$@ in 5 min" : { + "comment" : "Under the glucose value on the Now screen: the glucose unit and how much glucose changed over 5 minutes. (1: glucose unit, e.g. mmol/L; 2: signed change, e.g. +0.3)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ خلال ٥ دقائق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · %2$@ za 5 min" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ på 5 min" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ in 5 Min" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ en 5 min" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ / 5 min" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ en 5 min" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ ב-5 דק׳" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · %2$@ 5 perc alatt" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ in 5 min" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · 5分で%2$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ på 5 min" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ in 5 min" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ w 5 min" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ em 5 min" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ în 5 min" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ за 5 мин" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ za 5 min" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ på 5 min" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · 5 dk'da %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · %2$@ за 5 хв" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · %2$@ trong 5 phút" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ + %2$@" + "value" : "%1$@ · 5分钟内%2$@" } } } }, - "%1$@ APP SOUNDS" : { + "%1$@ · ending soon" : { + "comment" : "Status pill on the Now screen when a pump pod or CGM sensor is near the end of its life. (1: device name from the pump or CGM plugin, e.g. Omnipod 5)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · ينتهي قريبًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · brzy výměna" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · udløber snart" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · läuft bald ab" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · termina pronto" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · päättyy pian" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · fin proche" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · מסתיים בקרוב" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · hamarosan lejár" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · in scadenza" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · まもなく終了" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · utløper snart" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · verloopt binnenkort" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · wkrótce wymiana" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · terminando em breve" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · expiră curând" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · скоро замена" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · čoskoro výmena" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · går snart ut" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · yakında bitiyor" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · незабаром заміна" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · sắp hết hạn" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ · 即将到期" + } + } + } + }, + "%1$@%%" : { + "comment" : "A percentage. (1: number)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %%" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %%" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %%" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %%" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %%" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %%" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%%%1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%%" + } + } + } + }, + "%1$@%% basal" : { + "comment" : "Trends Insulin per day tile detail: share of insulin delivered as basal. (1: percentage number)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% القاعدية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazál %1$@%%" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% Basal" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basal" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basaalia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% Basal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル %1$@%%" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "baza %1$@%%" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basal" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% bazală" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "базал %1$@%%" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazál %1$@%%" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%%%1$@ bazal" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "базал %1$@%%" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础 %1$@%%" + } + } + } + }, + "%1$@%% basal · %2$@" : { + "comment" : "Trends Insulin per day tile detail when only some days are averaged. (1: basal share as a percentage number, 2: days averaged, e.g. 5 of 14 days)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% القاعدية · %2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazál %1$@%% · %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal · %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% Basal · %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basal · %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basaalia · %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal · %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% Basal · %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basal · %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basale · %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル %1$@%% · %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal · %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basaal · %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "baza %1$@%% · %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% basal · %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% bazală · %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "базал %1$@%% · %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazál %1$@%% · %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% basal · %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%%%1$@ bazal · %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "базал %1$@%% · %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% Basal · %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础 %1$@%% · %2$@" + } + } + } + }, + "%1$@%% CGM active" : { + "comment" : "Trends Time in range card: share of the period with CGM readings. (1: percentage number)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% CGM نشط" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM aktivní %1$@%%" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% CGM aktiv" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% CGM aktiv" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM activo %1$@%%" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% CGM aktiivinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM actif %1$@ %%" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% CGM פעיל" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% CGM aktív" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM attivo %1$@%%" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM稼働 %1$@%%" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% CGM aktiv" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% CGM actief" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM aktywny %1$@%%" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM ativo %1$@%%" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%% CGM activ" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM активен %1$@%%" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM aktívny %1$@%%" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %% CGM aktiv" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%%%1$@ CGM aktif" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM активний %1$@%%" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM hoạt động %1$@%%" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM 在线 %1$@%%" + } + } + } + }, + "%1$@, %2$@ %3$@: %4$@ percent, %5$@ hours a day" : { + "comment" : "VoiceOver label for a Time in range row. (1: band name, e.g. In range, 2: glucose thresholds, e.g. 3.9–10.0, 3: glucose unit, 4: percentage number, 5: average hours a day with one decimal)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@، %2$@ %3$@: %4$@ بالمئة، %5$@ ساعة يوميًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: procenta — %4$@, hodin denně — %5$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ procent, %5$@ timer om dagen" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ Prozent, %5$@ Stunden pro Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ por ciento, %5$@ horas al día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ prosenttia, %5$@ tuntia päivässä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@ : %4$@ pour cent, %5$@ heures par jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ אחוז, %5$@ שעות ביום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ százalék, napi %5$@ óra" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ percento, %5$@ ore al giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@、%2$@ %3$@:%4$@パーセント、1日%5$@時間" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ prosent, %5$@ timer i døgnet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ procent, %5$@ uur per dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: procent — %4$@, godzin dziennie — %5$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ por cento, %5$@ horas por dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ procente, %5$@ ore pe zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: процент — %4$@, часов в день — %5$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: percentá — %4$@, hodín denne — %5$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ procent, %5$@ timmar per dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: yüzde %4$@, günde %5$@ saat" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: відсоток — %4$@, годин на день — %5$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@ %3$@: %4$@ phần trăm, %5$@ giờ mỗi ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@,%2$@ %3$@:百分之%4$@,每天%5$@小时" + } + } + } + }, + "%lld days" : { + "comment" : "A number of days, e.g. a Trends period or how many days are averaged. (1: number of days) Trends period picker, VoiceOver name for a period of several days. (1: number of days)", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld day" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld days" + } + } + } + } + }, + "ar" : { + "variations" : { + "plural" : { + "zero" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld يوم" + } + }, + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld يوم" + } + }, + "two" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld يوم" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld أيام" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld يومًا" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld يوم" + } + } + } + } + }, + "cs" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld den" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dny" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dne" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dní" + } + } + } + } + }, + "da" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dag" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dage" + } + } + } + } + }, + "de" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Tag" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld Tage" + } + } + } + } + }, + "es" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld día" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld días" + } + } + } + } + }, + "fi" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld päivä" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld päivää" + } + } + } + } + }, + "fr" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld jour" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld jours" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld jours" + } + } + } + } + }, + "he" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld יום" + } + }, + "two" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld ימים" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld ימים" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld ימים" + } + } + } + } + }, + "hu" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld nap" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld nap" + } + } + } + } + }, + "it" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld giorno" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld giorni" + } + } + } + } + }, + "ja" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld日" + } + } + } + } + }, + "nb" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dag" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dager" + } + } + } + } + }, + "nl" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dag" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dagen" + } + } + } + } + }, + "pl" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dzień" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dni" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dni" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dnia" + } + } + } + } + }, + "pt-BR" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dia" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dias" + } + } + } + } + }, + "ro" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld zi" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld zile" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld de zile" + } + } + } + } + }, + "ru" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld день" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld дня" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld дней" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld дня" + } + } + } + } + }, + "sk" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld deň" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dni" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dňa" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dní" + } + } + } + } + }, + "sv" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dag" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld dagar" + } + } + } + } + }, + "tr" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld gün" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld gün" + } + } + } + } + }, + "uk" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld день" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld дні" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld днів" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld дня" + } + } + } + } + }, + "vi" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld ngày" + } + } + } + } + }, + "zh-Hans" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld天" + } + } + } + } + } + } + }, + "%lld shorter gaps" : { + "comment" : "Chart note: how many other, shorter gaps in glucose readings there were; follows the longest gap. (1: number of gaps)", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld shorter gap" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld shorter gaps" + } + } + } + } + }, + "ar" : { + "variations" : { + "plural" : { + "zero" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld فجوة أقصر" + } + }, + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld فجوة أقصر" + } + }, + "two" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld فجوة أقصر" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld فجوات أقصر" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld فجوة أقصر" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld فجوة أقصر" + } + } + } + } + }, + "cs" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratší výpadek" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratší výpadky" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratšího výpadku" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratších výpadků" + } + } + } + } + }, + "da" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortere hul" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortere huller" + } + } + } + } + }, + "de" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kürzere Lücke" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kürzere Lücken" + } + } + } + } + }, + "es" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interrupción más corta" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interrupciones más cortas" + } + } + } + } + }, + "fi" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld lyhyempi katko" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld lyhyempää katkoa" + } + } + } + } + }, + "fr" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interruption plus courte" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interruptions plus courtes" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interruptions plus courtes" + } + } + } + } + }, + "he" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld פער קצר יותר" + } + }, + "two" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld פערים קצרים יותר" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld פערים קצרים יותר" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld פערים קצרים יותר" + } + } + } + } + }, + "hu" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld rövidebb kimaradás" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld rövidebb kimaradás" + } + } + } + } + }, + "it" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interruzione più breve" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interruzioni più brevi" + } + } + } + } + }, + "ja" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "ほか短い欠損%lld件" + } + } + } + } + }, + "nb" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortere hull" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortere hull" + } + } + } + } + }, + "nl" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortere onderbreking" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortere onderbrekingen" + } + } + } + } + }, + "pl" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld krótsza przerwa" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld krótsze przerwy" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld krótszych przerw" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld krótszej przerwy" + } + } + } + } + }, + "pt-BR" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interrupção mais curta" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld interrupções mais curtas" + } + } + } + } + }, + "ro" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld întrerupere mai scurtă" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld întreruperi mai scurte" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld de întreruperi mai scurte" + } + } + } + } + }, + "ru" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld короткий пропуск" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротких пропуска" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротких пропусков" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротких пропуска" + } + } + } + } + }, + "sk" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratší výpadok" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratšie výpadky" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratšieho výpadku" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kratších výpadkov" + } + } + } + } + }, + "sv" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortare lucka" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld kortare luckor" + } + } + } + } + }, + "tr" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld daha kısa boşluk" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld daha kısa boşluk" + } + } + } + } + }, + "uk" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротший пропуск" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротші пропуски" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротших пропусків" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld коротшого пропуску" + } + } + } + } + }, + "vi" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld khoảng trống ngắn hơn" + } + } + } + } + }, + "zh-Hans" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "另有%lld段较短中断" + } + } + } + } + } + } + }, + "+ %1$@ automatic" : { + "comment" : "Trends Boluses per day tile detail: average number of automatic boluses per day on top of the manual ones, a fractional value such as 4.2. (1: number with one decimal)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ تلقائي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automat." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatiske" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatisch" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automáticos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automaattista" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatiques" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ אוטומטיים" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatikus" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatici" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ 自動 %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatiske" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatisch" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automat." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automáticos" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automate" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ авто" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automat." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ automatiska" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ otomatik" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ авто" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ %1$@ tự động" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "+ 自动 %1$@" + } + } + } + }, + "." : { + "comment" : "Full stop character", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "-" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "." + } + } + } + }, + "%@ %@" : { + "comment" : "The format for an active custom preset. (1: preset symbol)(2: preset name)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + } + } + }, + "%@ absorbed" : { + "comment" : "Formats absorbed carb value", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ استغرق" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ optaget" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ resorbiert" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorbido" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ imeytynyt" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorbé(s)" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ נספג" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ assorbiti" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ 吸収済" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorbert" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ geabsorbeerd" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ zaabsorbowane" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorvida" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorbiți" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ усвоено" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorbované" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ absorberat" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Emilen %@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ được hấp thụ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ 已吸收" + } + } + } + }, + "%@ remaining" : { + "comment" : "Estimated remaining duration with more than a minute", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ tilbage" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ verbleiben" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ restante" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ jäljellä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ restant" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ נותרו" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ rimanenti" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ gjenstår" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ resterend" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pozostało %@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ rămase" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Осталось %@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ återstår" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ kaldı" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "剩余 %@" + } + } + } + }, + "%@ U Total" : { + "comment" : "The subtitle format describing total insulin. (1: localized insulin total)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ وحدة بشكل كامل" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E Total" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ IE gesamt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U Totales" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U yhteensä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U total" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U סה״כ" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U Totali" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "計 %@ 単位" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E Totalt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E totaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ J łącznie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U Total" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U total" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ всего ед" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ j Celkom" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ E totalt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toplam %@ Ü" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ U Tổng cộng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ 单位 总量" + } + } + } + }, + "%@." : { + "comment" : "Appends a full-stop to a statement", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ ." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ ." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@." + } + } + } + }, + "%@%@ was unable to cancel your current temporary basal rate, which is higher than the new Max Basal limit you have set. This may result in higher insulin delivery than desired.\n\nConsider suspending insulin delivery manually and then immediately resuming to enact basal delivery with the new limit in place." : { + "comment" : "Alert text for failing to cancel temp basal (1: reason description, 2: app name)", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@ kunne ikke annullere din nuværende midlertidige basalrate, som er højere end den nye Max basalgrænse, du har indstillet. Dette kan resultere i en højere insulintilførsel end ønsket.\n\nOvervej at suspendere insulintilførslen manuelt og derefter straks genoptage den for at iværksætte basaltilførslen med den nye grænse på plads." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@ konnte Deine aktuelle temporäre Basalrate nicht abbrechen, da diese höher ist als die neue maximale Basalrate, die Du festgelegt hast. Dies kann zu einer höheren Insulinabgabe, als erwünscht führen.\n\nErwäge, die Insulinabgabe manuell zu unterbrechen und dann sofort wieder aufzunehmen, um die Basalabgabe mit dem neuen Grenzwert zu initiieren." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ no pudo cancelar su basal temporal actual, que es más alta que el nuevo límite basal máximo que ha establecido. Esto puede resultar en una administración de insulina superior a la deseada. \n\n Considere suspender la administración de insulina manualmente y luego reanudarla de inmediato para activar la administración basal con el nuevo límite establecido." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ n'a pas pu annuler votre débit basal temporaire actuel, qui est supérieur à la nouvelle limite basale max que vous avez définie. Cela peut entraîner une administration d'insuline plus élevée que souhaitée. \n\nEnvisagez de suspendre l'administration d'insuline manuellement, puis de reprendre immédiatement l'administration basale avec la nouvelle limite en place." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@ non sono stati in grado di cancellare la tua attuale basale temporanea, che è più elevata di quella impostata come nuovo limite massimo di basale. Questo potrebbe comportare una maggiore infusione d'insulina di quanto desiderato. \n\nConsidera di sospendere manualmente l'erogazione d'insulina e quindi di riattivarla immediatamente per attivare l'erogazione d'insulina basale con il corretto limite impostato." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ kunne ikke avbryte den nåværende midlertidige basaldosen, som er høyere enn den nye maksimale basalgrensen du har angitt. Dette kan føre til høyere insulintilførsel enn ønsket. \n\n Vurder å avbryte insulintilførselen manuelt og deretter umiddelbart gjenoppta for å innføre basaltilførsel med den nye grensen på plass." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@%@ kon je huidige tijdelijke basaalstand niet annuleren, die hoger is dan de nieuwe maximale basaallimiet die je hebt ingesteld. Dit kan leiden tot een hogere insulinetoediening dan gewenst. \n\nOverweeg om de insulinetoediening handmatig te onderbreken en dan direct het hervatten van de basaaltoediening uit te laten voeren met de nieuwe geldende limiet." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ nie mógł anulować bieżącej tymczasowej dawki podstawowej, która jest wyższa niż nowy ustawiony limit maksymalnej dawki podstawowej. Może to skutkować wyższym niż pożądane podawaniem insuliny. \n\n Rozważ ręczne wstrzymanie podawania insuliny, a następnie natychmiastowe wznowienie podawania dawki podstawowej z obowiązującym nowym limitem." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ nu a putut anula rata bazală temporară actuală, care este mai mare decât noua limită bazală maximă pe care ați setat-o. Acest lucru poate duce la o administrare de insulină mai mare decât se dorește. \n\nLuați în considerare suspendarea manuală a administrării insulinei și apoi reluarea imediată pentru a pune în aplicare administrarea bazală cu noua limită în vigoare." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@ не смог отменить вашу текущую ВБС, которая превышает установленный вами новый предел максимальной ВБС. Это может привести к большему количеству подаваемого инсулина, чем хотелось бы.\n\nРассмотрите возможность приостановить введение инсулина вручную, а затем немедленно возобновить введение базального инсулина с новым установленным лимитом." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@ nedokázal zrušiť vašu aktuálnu dočasnú bazálnu dávku, ktorá je vyššia ako nový maximálny bazálny limit, ktorý ste nastavili. To môže viesť k vyššiemu dodávaniu inzulínu, ako je požadované.\n\nZvážte ručné pozastavenie podávania inzulínu a následné okamžité obnovenie, aby ste uplatnili novým bazálny limit." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ , ayarladığınız yeni Maks Bazal limitinden daha yüksek olan mevcut geçici bazal oranınızı iptal edemedi. Bu, istenenden daha yüksek insülin iletimi ile sonuçlanabilir. \n\n İnsülin iletimini manuel olarak askıya almayı ve ardından yeni limit geçerliyken bazal iletimi etkinleştirmek için hemen devam etmeyi düşünün." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@%@ 无法取消当前的临时基础率,该基础率高于您新设定的最大基础率上限。这可能导致胰岛素输注量高于预期。\n\n建议您手动暂停胰岛素输注,然后立即恢复,以便根据新的上限重新执行基础输注。" + } + } + } + }, + "%1@%2@" : { + "comment" : "Adds a full-stop to a statement (1: statement, 2: full stop character)", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$1@%2$2@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$1@%2$2@" + } + } + } + }, + "%1$@ – %2$@ %3$@" : { + "comment" : "Format string for glucose target range. (1: Min target)(2: Max target)(3: glucose unit)", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - %2$@ %3$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – %2$@ %3$@" + } + } + } + }, + "%1$@ %2$@" : { + "comment" : "Format string combining carb entry quantity and absorption time emoji", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@%2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + } + } + }, + "%1$@ %2$@/U" : { + "comment" : "Format string for carb ratio average. (1: value)(2: carb unit)", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/وحدة" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/E" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/IE" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ /E" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ /E" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/J" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/ед" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ /j" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/E" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/Ü" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/U" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@/单位" + } + } + } + }, + "%1$@ + %2$@" : { + "comment" : "Format string combining carb entry time and absorption time\nFormats (1: carb start time) and (2: carb absorption duration)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ + %2$@" + } + } + } + }, + "%1$@ APP SOUNDS" : { "comment" : "App sounds title text (1: app name)", "localizations" : { "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ APP LYDE" + "value" : "%1$@ APP LYDE" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ SUONI DELL'APP" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ APP-LYDER" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ DŹWIĘKI APLIKACJI" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ЗВУКИ ПРИЛОЖЕНИЯ" + } + } + } + }, + "%1$@ is operating with Closed Loop in the OFF position. Your pump and CGM will continue operating, but the app will not adjust dosing automatically." : { + "comment" : "Alert message for closed loop off informational modal. (1: app name)", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kører med Lukket Loop i positionen OFF. Din pumpe og CGM fortsætter med at fungere, men appen justerer ikke doseringen automatisk." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ arbeitet mit geschlossenem Regelkreis in der AUS-Position. Deine Pumpe und CGM funktionieren weiter, aber die App passt die Dosierung nicht automatisch an." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ está funcionando con Circuito Cerrado en la posición APAGADO. Su bomba y CGM seguirán funcionando, pero la aplicación no ajustará la dosis automáticamente." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ fonctionne avec la boucle fermée en position ARRÊT. Votre pompe et votre CGM continueront de fonctionner, mais l'application n'ajustera pas automatiquement le dosage." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ è in funzione con Loop chiuso disattivato. La pompa e il CGM continueranno a funzionare, ma l'applicazione non regolerà automaticamente il dosaggio." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ opererer med Lukket Loop i AV-posisjon. Pumpen og CGM vil fortsette å fungere, men appen vil ikke justere doseringen automatisk." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ werkt met Actieve loop UIT. Je pomp en CGM blijven werken, maar de app past de dosering niet automatisch aan." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ działa z zamkniętą pętlą w pozycji OFF. Twoja pompa i CGM będą nadal działać, ale aplikacja nie będzie automatycznie dostosowywać insuliny." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ operează cu bucla închisă în poziția OPRIT. Pompa și senzorul de glicemie vor continua să funcționeze, dar aplicația nu va ajusta automat dozarea." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ работает с замкнутым циклом в положении ВЫКЛ. Ваша помпа и CGM будут продолжать работать, но приложение не будет регулировать дозировку автоматически." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ , KAPALI konumda Kapalı Döngü ile çalışıyor. Pompanız ve CGM çalışmaya devam edecek, ancak uygulama dozajı otomatik olarak ayarlamayacaktır." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 当前处于非闭环模式。胰岛素泵和连续血糖监测仪仍将正常运行,但应用程序不会自动调整胰岛素剂量。" + } + } + } + }, + "%1$@ is unable to clear the alert from your device" : { + "comment" : "Message for alert shown when alert acknowledgement fails for a device, and the device does not provide a LocalizedError. (1: app name)", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan ikke slette advarslen fra din enhed" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kann die Benachrichtigung nicht von Deinem Gerät löschen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ no puede borrar la alerta de su dispositivo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ne parvient pas à supprimer l'alerte de votre dispositif." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ non è in grado di cancellare l'avviso dal tuo dispositivo" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan ikke fjerne varselet fra enheten din" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan de melding niet wissen van je apparaat" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nie może usunąć alertu z Twojego urządzenia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nu poate șterge alerta de pe dispozitiv" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ не удается удалить предупреждение с вашего устройства" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ , uyarıyı cihazınızdan silemiyor" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 无法清除您设备上的警报。" + } + } + } + }, + "%1$@ is unable to communicate with your insulin pump. The app will continue trying to reach your pump, but insulin delivery information cannot be updated and no automation can continue.\nYou can wait several minutes to see if the issue resolves or tap the button below to learn more about other options." : { + "comment" : "Message for alert shown when delivery status is uncertain. (1: app name)", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan ikke kommunikere med insulinpumpen. Loop vil fortsætte med at forsøge at kommunikere med din pumpe, men insulinafgivelsesoplysninger kan ikke opdateres og ingen automatisering kan fortsætte.\nDu kan vente et par minutter for at se, om problemet bliver løst, eller tryk på knappen nedenfor for at få mere at vide om andre muligheder." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kann nicht mit Deiner Insulinpumpe kommunizieren. Die App versucht weiterhin, Deine Pumpe zu erreichen, aber die Informationen zur Insulinabgabe können nicht aktualisiert werden und die Automatisierung kann nicht fortgesetzt werden.\nDu kannst einige Minuten warten, um zu sehen, ob das Problem behoben ist, oder auf die Schaltfläche unten tippen, um mehr über andere Optionen zu erfahren." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ no puede comunicarse con tu bomba de insulina. La aplicación continuará intentando llegar a tu bomba, pero la información de entrega de insulina no se puede actualizar y ninguna automatización puede continuar.\nPuedes esperar varios minutos para ver si el problema resuelve o pulsa el botón de abajo para saber más sobre otras opciones." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ei pysty kommunikoimaan insuliinipumpun kanssa. Sovellus yrittää edelleen yhdistää pumppuun, mutta insuliininannostelun tiedot eivät päivity, eikä automatiikka ole päällä.\nVoit odottaa muutaman minuutin nähdäksesi ratkeaako ongelma, tai voit napauttaa alla olevaa painiketta saadaksesi lisätietoja muista vaihtoehdoista." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ne parvient pas à communiquer avec votre pompe à insuline. L’application continuera d’essayer d’atteindre votre pompe, mais les informations sur l’administration d’insuline ne peuvent pas être mises à jour et aucune automatisation ne peut continuer.\nVous pouvez attendre quelques minutes pour voir si le problème est résolu ou appuyer sur le bouton ci-dessous pour en savoir plus sur les autres options." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ non riesce a comunicare con la pompa. L'app continuerà a provare a contattare la pompa, ma le informazioni sull'erogazione dell'insulina non possono essere aggiornate e l'automazione non può proseguire. \nPuoi attendere alcuni minuti per vedere se il problema si risolve oppure toccare il pulsante qui sotto per saperne di più sulle altre opzioni." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan ikke kommunisere med insulinpumpen. Appen vil fortsette å prøve å nå pumpen din, men insulintilførselsinformasjon kan ikke oppdateres og ingen automatisering kan fortsette.\n Du kan vente flere minutter for å se om problemet løser seg eller trykke på knappen nedenfor for å lære mer om andre alternativer." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan niet communiceren met je insulinepomp. De app blijft proberen je pomp te bereiken, maar de insulinetoedieningsinformatie kan niet worden bijgewerkt en automatisering kan niet plaatsvinden.\nJe kunt enkele minuten wachten om te zien of het probleem is opgelost of tik op de onderstaande knop voor meer informatie over andere opties." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nie może skomunikować się z Twoją pompą insulinową. Aplikacja będzie nadal próbowała połączyć się z pompą, ale nie można aktualizować informacji o podawaniu insuliny i nie można kontynuować automatyzacji.\n Możesz poczekać kilka minut, aby sprawdzić, czy problem został rozwiązany, lub nacisnąć poniższy przycisk, aby dowiedzieć się więcej o innych opcjach." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nu poate comunica cu pompa de insulină. Aplicația va continua să încerce să comunice cu pompa, dar informațiile despre administrarea insulinei nu pot fi actualizate și automatizarea nu poate continua.\nPuteți aștepta câteva minute pentru a vedea dacă problema se rezolvă sau apăsați butonul de mai jos pentru a afla mai multe despre alte opțiuni." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ не может связаться с вашей инсулиновой помпой. Приложение будет продолжать попытки связаться с вашей помпой, но информация о доставке инсулина не может быть обновлена, и автоматизация не может продолжаться.\nВы можете подождать несколько минут и посмотреть, разрешится ли проблема, или нажать кнопку ниже, чтобы узнать о других возможностях." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nedokáže komunikovať s vašou inzulínovou pumpou. Aplikácia sa bude naďalej pokúšať kontaktovať vašu pumpu, ale informácie o podávaní inzulínu nemožno aktualizovať a nemôže pokračovať žiadna automatizácia.\nMôžete počkať niekoľko minút, aby ste zistili, či sa problém vyriešil, alebo klepnutím na tlačidlo nižšie sa dozviete viac o ďalších možnostiach." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kan inte kommunicera med din insulinpump. Appen kommer att fortsätta att försöka nå din pump, men under tiden kan information om insulintillförsel inte uppdateras och automatisering inte fortsätta.\nDu kan vänta flera minuter för att se om problemet löser sig eller klicka på knappen nedan för att läsa mer om andra alternativ." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ insülin pompanızla iletişim kuramıyor. Uygulama pompanıza ulaşmaya çalışmaya devam edecek, ancak insülin iletim bilgileri güncellenemeyecek ve hiçbir otomasyon devam edemeyecektir.\nSorunun çözülüp çözülmediğini görmek için birkaç dakika bekleyebilir veya diğer seçenekler hakkında daha fazla bilgi edinmek için aşağıdaki butona dokunabilirsiniz." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 无法与您的胰岛素泵通信。应用将继续尝试连接胰岛素泵,但当前无法更新胰岛素输注信息,也无法继续自动化操作。\n\n您可以等待几分钟以观察问题是否自动恢复,或点击下方按钮了解其他可选操作。" + } + } + } + }, + "%1$@ Time Settings Need Attention" : { + "comment" : "Time change alert title", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Tidsindstillinger kræver opmærksomhed" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Zeiteinstellungen erfordern Aufmerksamkeit" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ La configuración de la hora necesita atención" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Paramètres d'heure requierent une attention" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ הגדרות השעה דורשות תשומת לב" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Le impostazioni dell'orario richiedono attenzione" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Tidsinnstillinger trenger oppmerksomhet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Tijdinstellingen hebben aandacht nodig" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ustawienia czasu wymagają uwagi" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Setările de timp necesită atenție" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Настройки времени требуют внимания" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Zaman Ayarlarına Dikkat Edilmesi Gerekiyor" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 时间设置需要注意" + } + } + } + }, + "%1$@ U" : { + "comment" : "Reservoir entry (1: volume value)", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ IE" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "U %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ J" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ед." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ j" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ü" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ وحدة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 単位" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U" + } + } + } + }, + "%1$@ U left" : { + "comment" : "Low reservoir alert format string. (1: Number of units remaining)", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ وحدة متبقية" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E tilbage" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ IE verbleibend" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U left" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U restantes" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U jäljellä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U restantes" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U נותרו" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U rimaste" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "残 %1$@単位" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E igjen" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E over" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ J pozostało" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U restante" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U rămase" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ед осталось" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zostáva %1$@ j" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E kvar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ü kaldı" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U còn lại" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 单位 剩余" + } + } + } + }, + "%1$@ U left: %2$@" : { + "comment" : "Low reservoir alert with time remaining format string. (1: Number of units remaining)(2: approximate time remaining)", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ وحدة متبقية: %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E tilbage: %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ IE verbleibend: %2$@" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U left: %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U restantes: %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U jäljellä: %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U restantes: %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U נותרו: %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U rimaste: %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "残 %1$@単位: %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E gjenstår: %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E over: %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ J pozostało: %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U restante: %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U rămase: %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ед осталось: %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zostáva %1$@ j: %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E kvar: %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ü kalan: %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U còn lại: %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 单位 剩余: %2$@" + } + } + } + }, + "%1$@ U/hour @ %2$@" : { + "comment" : "The format for recommended temp basal rate and time. (1: localized rate number)(2: localized time)", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ وحدة/ساعة @ %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E/time @ %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ IE/h @ %2$@" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/hour @ %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/hora @ %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/h klo %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/heure @ %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ יח׳/שעה @ %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/ora @ %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/時 @ %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E/timen @ %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E/uur @ %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ J/godzinę @ %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/hora @ %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/oră @ %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ед/час @ %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ j/hod @ %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ E/h @ %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ Ü/saat @ %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ U/giờ @ %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 单位/小时 @ %2$@" + } + } + } + }, + "%1$@ v%2$@" : { + "comment" : "The format string for the app name and version number. (1: bundle name)(2: bundle version)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ версии %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ v%2$@" + } + } + } + }, + "%1$@ will stop working in %2$@. You will need to rebuild before that." : { + "comment" : "Format string for body for notification of upcoming expiration. (1: app name) (2: amount of time until expiration", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ holder op med at fungere i %2$@. Du bliver nødt til at rebuilde før det." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ funktioniert in %2$@ nicht mehr. Sie müssen vorher einen Neuaufbau durchführen." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ cessera de fonctionner dans %2$@. Il vous faudra recompiler avant cette échéance." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ smetterà di funzionare tra %2$@. Prima di allora, sarà necessario ricostruirlo." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ vil slutte å fungere i %2$@. Du må gjenoppbygge før det." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ stopt over %2$@ met werken. Bouw de app vóór die tijd opnieuw." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ przestanie działać w %2$@. Konieczna będzie wcześniejsza odbudowa." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ va înceta să funcționeze în %2$@. Va trebui să reconstruiți sistemul înainte de asta." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ перестанет работать в %2$@. До этого времени необходимо пересобрать приложение заново." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@将在%2$@停止工作。您需要在此之前重建。" + } + } + } + }, + "%1$@ will stop working in %2$@. You will need to update before that, with a new provisioning profile." : { + "comment" : "Format string for body for notification of upcoming provisioning profile expiration. (1: app name) (2: amount of time until expiration", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ holder op med at fungere i %2$@. Du skal opdatere inden da med en ny provisioneringsprofil." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ funktioniert nicht mehr in %2$@. Du musst vor Ablauf mit einem neuen Bereitstellungsprofil aktualisieren." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ dejará de funcionar en %2$@ . Deberá actualizar antes de eso, con un nuevo perfil de aprovisionamiento." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ cessera de fonctionner dans %2$@ . Vous devrez mettre à jour avant cela, avec un nouveau profil de provisioning." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ smetterà di funzionare tra %2$@. Prima di allora, sarà necessario effettuare l'aggiornamento con un nuovo profilo di provisioning." + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ slutter å fungere om %2$@ . Du må oppdatere før det, med en ny klargjøringsprofil." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ stopt met werken in %2$@. Je zult eerder moeten updaten, met een nieuw beschikbaargesteld profiel." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ przestanie działać za %2$@ . Wcześniej konieczna będzie aktualizacja przy użyciu nowego profilu udostępniania." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ nu va mai funcționa în %2$@. Va trebui să actualizați înainte de aceasta, cu un nou profil de asigurare a accesului." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ перестанет работать в %2$@. Вам нужно будет обновить его до этого, используя новую подпись." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@ içinde çalışmayı durduracaktır. Bundan önce yeni bir provizyon profili ile güncelleme yapmanız gerekecektir." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ 在 %2$@中将无法正常工作。您需要在该版本发布之前,使用新的配置文件进行更新。" + } + } + } + }, + "%1$@: %2$@" : { + "comment" : "Formats (1: carb value) and (2: food type)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ : %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ : %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ : %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" + } + } + } + }, + "%1$@: %2$@ %3$@" : { + "comment" : "Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit)\nDescription of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit)", + "localizations" : { + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ : %2$@ %3$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@ %3$@" + } + } + } + }, + "25–75%" : { + "comment" : "Trends Daily pattern legend: band between the 25th and 75th percentiles of glucose", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75 %" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75 %" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75 %" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75 %" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%25–75" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "25–75%" + } + } + } + }, + "5–95%" : { + "comment" : "Trends Daily pattern legend: band between the 5th and 95th percentiles of glucose", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95 %" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95 %" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95 %" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95 %" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%5–95" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "5–95%" + } + } + } + }, + "absorbs over %1$@ h" : { + "comment" : "Logbook carb row detail: carb absorption time in hours. (1: hours, e.g. 3 or 2.5)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يُمتص خلال %1$@ س" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "vstřebání za %1$@ h" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "optages over %1$@ t" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aufnahme über %1$@ Std" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "se absorbe en %1$@ h" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "imeytyy %1$@ h:ssa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "absorption sur %1$@ h" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נספג במשך %1$@ שע׳" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ óra alatt szívódik fel" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "assorbimento in %1$@ h" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@時間で吸収" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "absorberes over %1$@ t" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "opname in %1$@ u" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "wchłanianie przez %1$@ godz." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "absorve em %1$@ h" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "se absoarbe în %1$@ h" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "усваивается за %1$@ ч" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "vstrebanie za %1$@ h" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "absorberas under %1$@ h" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ sa içinde emilir" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "засвоюється за %1$@ год" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "hấp thu trong %1$@ giờ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@小时内吸收" + } + } + } + }, + "Active insulin %1$@, active carbs %2$@" : { + "comment" : "VoiceOver summary of the active insulin and carbs chart. (1: insulin on board, e.g. 1.25 U, or unknown; 2: carbs on board, e.g. 20 g, or unknown)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الأنسولين النشط %1$@، الكارب النشط %2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivní inzulín %1$@, aktivní sacharidy %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivt insulin %1$@, aktive kulhydrater %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktives Insulin %1$@, aktive KH %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina activa %1$@, carbohidratos activos %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Akt. insuliini %1$@, akt. hiilari %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline active %1$@, glucides actifs %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אינסולין פעיל %1$@, פחמימות פעילות %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktív inzulin %1$@, aktív szénhidrát %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina attiva %1$@, carboidrati attivi %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "残存インスリン %1$@、残存糖質 %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivt insulin %1$@, aktive karbohydrater %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve insuline %1$@, actieve koolhydraten %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktywna insulina %1$@, aktywne węglowodany %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina ativa %1$@, carboidratos ativos %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulină activă %1$@, carbohidrați activi %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активный инсулин %1$@, активные углеводы %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktívny inzulín %1$@, aktívne sacharidy %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivt insulin %1$@, aktiva kolhydrater %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktif insülin %1$@, aktif karb %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активний інсулін %1$@, активні вуглеводи %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin còn hoạt động %1$@, Carbs còn hoạt động %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "活性胰岛素 %1$@,活性碳水 %2$@" + } + } + } + }, + "Active insulin and carbs" : { + "comment" : "Title of the day page card charting insulin and carbs on board", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الأنسولين والكارب النشطان" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivní inzulín a sacharidy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivt insulin og kulhydrater" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktives Insulin und KH" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina y carbohidratos activos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktiivinen insuliini ja hiilihydraatit" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline et glucides actifs" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אינסולין ופחמימות פעילים" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktív inzulin és szénhidrát" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina e carboidrati attivi" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "残存インスリンと残存糖質" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivt insulin og karbohydrater" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve insuline en koolhydraten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktywna insulina i węglowodany" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina e carboidratos ativos" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulină activă și carbohidrați activi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активный инсулин и углеводы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktívny inzulín a sacharidy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktivt insulin och kolhydrater" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktif insülin ve karb" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активний інсулін і вуглеводи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin và Carbs còn hoạt động" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "活性胰岛素和碳水" + } + } + } + }, + "Add carbs" : { + "comment" : "Button on the Now screen that opens carb entry", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إضافة كارب" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Přidat sacharidy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tilføj kulhydrater" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "KH hinzufügen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar carbohidratos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lisää hiilihydraatteja" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter des glucides" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הוספת פחמימות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Szénhidrát hozzáadása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungi carboidrati" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "カーボを追加" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Legg til karbohydrater" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Koolhydraten toevoegen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj węglowodany" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar carbs" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adăugați carbohidrați" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить углеводы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pridať sacharidy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lägg till kolhydrater" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karb ekle" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додати вуглеводи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thêm Carbs" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "添加碳水" + } + } + } + }, + "Add pump" : { + "comment" : "Status pill on the Now screen when no pump is set up; tapping it starts pump setup", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إضافة مضخة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Přidat pumpu" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tilføj pumpe" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpe hinzufügen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar microinfusadora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lisää pumppu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter une pompe" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הוספת משאבה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa hozzáadása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungi pompa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプを追加" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Legg til pumpe" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pomp toevoegen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj pompę" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar bomba" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adăugați pompă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить помпу" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pridať pumpu" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lägg till pump" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa ekle" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додати помпу" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thêm bơm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "添加胰岛素泵" + } + } + } + }, + "Aim: over 70%% in range, under 4%% low." : { + "comment" : "Trends Time in range card footnote: the consensus targets for time in range and time low", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الهدف: أكثر من 70%% ضمن النطاق، وأقل من 4%% منخفض." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cíl: přes 70%% v rozsahu, pod 4%% nízko." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mål: over 70 %% i området, under 4 %% lavt." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ziel: über 70 %% im Zielbereich, unter 4 %% niedrig." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Objetivo: más del 70%% en rango, menos del 4%% bajo." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tavoite: yli 70 %% tavoitealueella, alle 4 %% matalalla." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Objectif : plus de 70 %% dans la cible, moins de 4 %% en hypo." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "יעד: מעל 70%% בטווח, מתחת ל-4%% נמוך." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cél: több mint 70%% tartományban, kevesebb mint 4%% alacsony." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obiettivo: oltre il 70%% nell'intervallo, meno del 4%% bassa." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "目標:範囲内70%%超、低値4%%未満。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mål: over 70 %% i målområdet, under 4 %% lavt." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Doel: meer dan 70%% binnen bereik, minder dan 4%% laag." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cel: ponad 70%% w zakresie, poniżej 4%% niskich." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meta: mais de 70%% no alvo, menos de 4%% baixo." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Țintă: peste 70%% în interval, sub 4%% scăzut." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Цель: в диапазоне более 70%%, низкая — менее 4%%." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cieľ: nad 70%% v rozsahu, pod 4%% nízko." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mål: över 70 %% inom målområdet, under 4 %% lågt." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hedef: aralıkta %%70'in üzeri, düşükte %%4'ün altı." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мета: у діапазоні понад 70%%, низька — менше 4%%." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mục tiêu: trên 70%% trong khoảng, dưới 4%% thấp." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "目标:范围内超过70%%,低血糖低于4%%。" + } + } + } + }, + "All" : { + "comment" : "Logbook filter chip: show every entry", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الكل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vše" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Todo" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kaikki" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tout" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הכל" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mind" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tutto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "すべて" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alles" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wszystko" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tudo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toate" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Все" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Všetko" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alla" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tümü" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Усі" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tất cả" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "全部" + } + } + } + }, + "App Icon" : { + "comment" : "Header for the app icon choice", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "أيقونة التطبيق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikona aplikace" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appsymbol" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "App-Symbol" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Icono de la app" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sovelluksen kuvake" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Icône de l'app" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "צלמית היישום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alkalmazásikon" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Icona dell'app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "アプリアイコン" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appsymbol" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "App-symbool" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikona aplikacji" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ícone do app" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pictograma aplicației" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Значок приложения" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikona aplikácie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appsymbol" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uygulama Simgesi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Іконка програми" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Biểu tượng ứng dụng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "App 图标" + } + } + } + }, + "Appearance" : { + "comment" : "Title of the appearance settings screen Title of the light or dark appearance choice", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المظهر" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vzhled" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Udseende" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Darstellung" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apariencia" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ulkoasu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apparence" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מראה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megjelenés" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aspetto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "外観" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utseende" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Weergave" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wygląd" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aparência" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aspect" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Оформление" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vzhľad" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utseende" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Görünüm" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вигляд" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giao diện" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "外观" + } + } + } + }, + "Appearance and App Icon" : { + "comment" : "Title of the row that opens the appearance and app icon settings", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المظهر وأيقونة التطبيق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vzhled a ikona aplikace" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Udseende og appsymbol" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Darstellung und App-Symbol" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apariencia e icono de la app" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ulkoasu ja sovelluksen kuvake" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apparence et icône de l'app" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מראה וצלמית היישום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megjelenés és alkalmazásikon" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aspetto e icona dell'app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "外観とアプリアイコン" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utseende og appsymbol" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Weergave en app-symbool" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wygląd i ikona aplikacji" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aparência e ícone do app" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aspect și pictograma aplicației" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Оформление и значок" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vzhľad a ikona aplikácie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utseende och appsymbol" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Görünüm ve Uygulama Simgesi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вигляд та іконка" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giao diện và biểu tượng ứng dụng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "外观与 App 图标" + } + } + } + }, + "Automatic" : { + "comment" : "Chart legend: outlined bars are automatic boluses given by Loop", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تلقائي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatické" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisk" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisch" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automático" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automaattinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatique" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אוטומטי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatikus" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatico" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "自動" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisk" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisch" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatyczne" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automático" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Автоматические" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatické" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisk" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otomatik" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Автоматичні" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tự động" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "自动" + } + } + } + }, + "Automatic bolus" : { + "comment" : "Chart callout label for a bolus Loop delivered automatically near the touched time Logbook row title: a bolus Loop delivered automatically", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus تلقائي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatický bolus" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisk bolus" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatischer Bolus" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolo automático" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automaattinen bolus" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus automatique" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus אוטומטי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatikus bólus" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolo automatico" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "自動ボーラス" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisk bolus" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatische bolus" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus automatyczny" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus automático" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus automat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Автоматический болюс" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatický bolus" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisk bolus" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otomatik bolus" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Автоматичний болюс" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus tự động" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "自动大剂量" + } + } + } + }, + "Average" : { + "comment" : "Trends summary tile: mean glucose over the period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المتوسط" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Průměr" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gennemsnit" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Durchschnitt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Promedio" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keskiarvo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moyenne" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ממוצע" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Átlag" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Media" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "平均" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gjennomsnitt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gemiddeld" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Średnia" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Média" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medie" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Среднее" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priemer" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medelvärde" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ortalama" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Середнє" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trung bình" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "平均值" + } + } + } + }, + "Average %1$@ U" : { + "comment" : "Trends Insulin per day legend: the dashed line showing average total insulin per day. (1: units)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المتوسط %1$@ وحدة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Průměr %1$@ U" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gennemsnit %1$@ E" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Durchschnitt %1$@ IE" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Promedio %1$@ U" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keskiarvo %1$@ U" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moyenne %1$@ U" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ממוצע U %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Átlag %1$@ U" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Media %1$@ U" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "平均 %1$@ 単位" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gjennomsnitt %1$@ E" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gemiddeld %1$@ E" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Średnio %1$@ J" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Média %1$@ U" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medie %1$@ U" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Среднее %1$@ Ед." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Priemer %1$@ j" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medel %1$@ E" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ortalama %1$@ Ü" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Середнє %1$@ U" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trung bình %1$@ U" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "平均 %1$@ U" + } + } + } + }, + "Basal" : { + "comment" : "Chart callout label for the basal rate at the touched time Label of a tile showing the current basal rate (Now screen) or the day's basal insulin total (Today so far totals) Logbook filter chip: show only basal changes", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القاعدية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaalinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podstawowy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazálna" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazal" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础" + } + } + } + }, + "Basal %1$@ U (%2$@%%)" : { + "comment" : "Trends Insulin per day legend: average basal insulin per day and its share of the total. (1: units, 2: percentage number)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القاعدية %1$@ وحدة (%2$@%%)" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál %1$@ U (%2$@%%)" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ E (%2$@ %%)" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ IE (%2$@ %%)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ U (%2$@%%)" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaali %1$@ U (%2$@ %%)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ U (%2$@ %%)" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal U %1$@ (%2$@%%)" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ U (%2$@%%)" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale %1$@ U (%2$@%%)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル %1$@ 単位(%2$@%%)" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ E (%2$@ %%)" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaal %1$@ E (%2$@%%)" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baza %1$@ J (%2$@%%)" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ U (%2$@%%)" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală %1$@ U (%2$@%%)" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал %1$@ Ед. (%2$@%%)" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál %1$@ j (%2$@%%)" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ E (%2$@ %%)" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazal %1$@ Ü (%%%2$@)" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал %1$@ U (%2$@%%)" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal %1$@ U (%2$@%%)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础 %1$@ U(%2$@%%)" + } + } + } + }, + "Basal adjustments" : { + "comment" : "Logbook row title summarising the temp basals Loop set in a day Title of the list of every temp basal Loop set in a day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعديلات القاعدية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Úpravy bazálu" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaljusteringer" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basalanpassungen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajustes de basal" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaalisäädöt" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajustements du basal" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "התאמות Basal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal-módosítások" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Regolazioni basale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル調整" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaljusteringer" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaalaanpassingen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zmiany bazy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajustes de basal" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajustări bazală" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изменения базала" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Úpravy bazálu" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaljusteringar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazal ayarlamaları" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Зміни базалу" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Điều chỉnh Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础率调整" + } + } + } + }, + "basal and bolus" : { + "comment" : "Trends Insulin per day card subtitle when each bar is one day's basal and bolus", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القاعدية و Bolus" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazál a bolus" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal og bolus" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal und Bolus" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal y bolo" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "basaali ja bolus" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal et bolus" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal ו-Bolus" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal és bólus" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "basale e bolo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサルとボーラス" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal og bolus" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "basaal en bolus" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "baza i bolus" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal e bolus" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazală și bolus" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "базал и болюс" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazál a bolus" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "basal och bolus" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "bazal ve bolus" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "базал і болюс" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal và Bolus" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础和大剂量" + } + } + } + }, + "Basal given" : { + "comment" : "Chart legend: filled area is basal insulin actually delivered", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القاعدية المُعطاة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podaný bazál" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Givet basal" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abgegebene Basalrate" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal administrada" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Annettu basaali" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal administré" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal שניתן" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Leadott basal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale erogata" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "注入済みベーサル" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gitt basal" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toegediend basaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podana baza" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal entregue" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală administrată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поданный базал" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podaný bazál" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Given basal" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verilen bazal" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поданий базал" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal đã tiêm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已输注基础" + } + } + } + }, + "Basal resumed" : { + "comment" : "Logbook row title: insulin delivery resumed after a suspend", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "استئناف القاعدية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál obnoven" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal genoptaget" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal fortgesetzt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal reanudada" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaali jatkuu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal repris" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal חודש" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal folytatva" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale ripresa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル再開" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal gjenopptatt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaal hervat" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baza wznowiona" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal retomada" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală reluată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал возобновлён" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál obnovený" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal återupptagen" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazal devam ettirildi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал відновлено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã tiếp tục Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础已恢复" + } + } + } + }, + "Basal suspended" : { + "comment" : "Logbook row title: insulin delivery was suspended", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إيقاف القاعدية مؤقتًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál pozastaven" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal suspenderet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal unterbrochen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal suspendida" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaali pysäytetty" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal suspendu" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal הושהה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal felfüggesztve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale sospesa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ベーサル一時停止" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal stanset" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basaal onderbroken" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baza wstrzymana" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal suspensa" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală suspendată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал приостановлен" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazál pozastavený" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal pausad" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazal askıya alındı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Базал призупинено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã tạm ngưng Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "基础已暂停" + } + } + } + }, + "Bolus %1$@ U (%2$@%%)" : { + "comment" : "Trends Insulin per day legend: average bolus insulin per day and its share of the total. (1: units, 2: percentage number)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ وحدة (%2$@%%)" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ U (%2$@%%)" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ E (%2$@ %%)" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ IE (%2$@ %%)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolo %1$@ U (%2$@%%)" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ U (%2$@ %%)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ U (%2$@ %%)" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus U %1$@ (%2$@%%)" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bólus %1$@ U (%2$@%%)" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolo %1$@ U (%2$@%%)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ボーラス %1$@ 単位(%2$@%%)" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ E (%2$@ %%)" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ E (%2$@%%)" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ J (%2$@%%)" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ U (%2$@%%)" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ U (%2$@%%)" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюс %1$@ Ед. (%2$@%%)" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ j (%2$@%%)" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ E (%2$@ %%)" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ Ü (%%%2$@)" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюс %1$@ U (%2$@%%)" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus %1$@ U (%2$@%%)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "大剂量 %1$@ U(%2$@%%)" + } + } + } + }, + "Boluses per day" : { + "comment" : "Trends summary tile: average number of manual boluses per day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "جرعات Bolus يوميًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolusů denně" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boluser pr. dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boli pro Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolos por día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boluksia päivässä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus par jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus ליום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bólusok naponta" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boli al giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日のボーラス回数" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boluser per dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolussen per dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolusy dziennie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus por dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolusuri pe zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюсов в день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolusy za deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolusar per dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük bolus sayısı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюсів на день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Số lần Bolus mỗi ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日大剂量次数" + } + } + } + }, + "Carbs" : { + "comment" : "Label of a tile showing the day's total carbohydrate Logbook filter chip: show only carb entries Logbook row title: a carb entry", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbs" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sacharidy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kulhydrater" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "KH" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbohidratos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hiilihydraatit" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucides" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbs" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Szénhidrát" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carb." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "カーボ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karbohydrater" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Koolhydraten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Węglowodany" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbs" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbohidrați" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Углеводы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sacharidy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kolhydrater" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karb" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вуглеводи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbs" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "碳水化合物" + } + } + } + }, + "Carbs per day" : { + "comment" : "Trends summary tile: average grams of carbohydrate entered per day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الكارب يوميًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sacharidy denně" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kulhydrater pr. dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "KH pro Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbohidratos por día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hiilihydraatit päivässä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucides par jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פחמימות ליום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Szénhidrát naponta" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carboidrati al giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日のカーボ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karbohydrater per dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Koolhydraten per dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Węglowodany dziennie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbs por dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbohidrați pe zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Углеводов в день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sacharidy za deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kolhydrater per dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük karb" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вуглеводів на день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Carbs mỗi ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日碳水" + } + } + } + }, + "Changes with the home screen's light or dark appearance" : { + "comment" : "Description of the app icon that follows the home screen appearance", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تتغير مع المظهر الفاتح أو الداكن للشاشة الرئيسية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mění se podle světlého nebo tmavého vzhledu plochy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Skifter med hjemmeskærmens lyse eller mørke udseende" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wechselt mit der hellen oder dunklen Darstellung des Home-Bildschirms" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cambia con la apariencia clara u oscura de la pantalla de inicio" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vaihtuu kotinäytön vaalean tai tumman ulkoasun mukaan" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suit l'apparence claire ou sombre de l'écran d'accueil" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "משתנה בהתאם למראה הבהיר או הכהה של מסך הבית" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A kezdőképernyő világos vagy sötét megjelenését követi" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cambia con l'aspetto chiaro o scuro della schermata Home" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ホーム画面のライト/ダークに合わせて変わります" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endres med det lyse eller mørke utseendet på Hjem-skjermen" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Past zich aan de lichte of donkere weergave van het beginscherm aan" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zmienia się wraz z jasnym lub ciemnym wyglądem ekranu początkowego" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Muda com a aparência clara ou escura da tela de início" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se schimbă după aspectul luminos sau întunecat al ecranului principal" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Меняется вместе со светлым или тёмным оформлением экрана «Домой»" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mení sa podľa svetlého alebo tmavého vzhľadu plochy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Följer hemskärmens ljusa eller mörka utseende" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ana ekranın açık veya koyu görünümüne göre değişir" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Змінюється разом зі світлим або темним виглядом початкового екрана" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thay đổi theo giao diện sáng hoặc tối của màn hình chính" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "随主屏幕的浅色或深色外观变化" + } + } + } + }, + "Classic" : { + "comment" : "Name of Loop's original app icon", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "كلاسيكي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klasická" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klassisk" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klassisch" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clásico" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klassinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Classique" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קלאסי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klasszikus" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Classica" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クラシック" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klassisk" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klassiek" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klasyczna" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clássico" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clasică" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Классический" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klasická" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klassisk" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Klasik" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Класична" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cổ điển" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "经典" + } + } + } + }, + "Closed loop" : { + "comment" : "Trends Loop status: time Loop was running in closed loop", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مغلقة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环" + } + } + } + }, + "Closed loop is off: Loop recommends but doesn't adjust insulin." : { + "comment" : "Message in the alert shown when tapping the Loop status on the Now screen while closed loop is off", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الحلقة المغلقة متوقفة: يقدّم Loop توصيات لكنه لا يعدّل الأنسولين." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka je vypnutá: Loop doporučuje, ale inzulín neupravuje." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop er slået fra: Loop anbefaler, men justerer ikke insulin." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop ist aus: Loop empfiehlt, passt das Insulin aber nicht an." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El circuito cerrado está desactivado: Loop recomienda pero no ajusta la insulina." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö on pois päältä: Loop suosittelee, mutta ei säädä insuliinia." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "La boucle fermée est désactivée : Loop recommande mais n'ajuste pas l'insuline." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop כבוי: Loop ממליץ אך אינו מתאים את האינסולין." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A zárt hurok ki van kapcsolva: a Loop javasol, de nem módosítja az inzulint." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il loop chiuso è disattivato: Loop suggerisce ma non regola l'insulina." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループはオフです:Loopは推奨のみ行い、インスリンを調整しません。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop er av: Loop anbefaler, men justerer ikke insulin." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop staat uit: Loop geeft advies maar past de insuline niet aan." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta jest wyłączona: Loop zaleca, ale nie dostosowuje insuliny." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O ciclo fechado está desligado: o Loop recomenda, mas não ajusta a insulina." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bucla închisă este oprită: Loop recomandă, dar nu ajustează insulina." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл выключен: Loop даёт рекомендации, но не регулирует инсулин." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka je vypnutá: Loop odporúča, ale inzulín neupravuje." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop är av: Loop ger förslag men justerar inte insulinet." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü kapalı: Loop öneride bulunur ancak insülini ayarlamaz." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл вимкнено: Loop дає рекомендації, але не регулює інсулін." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín đang tắt: Loop chỉ đưa ra khuyến nghị và không điều chỉnh insulin." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环已关闭:Loop 只给出建议,不会调整胰岛素。" + } + } + } + }, + "Closed loop is on." : { + "comment" : "Message in the alert shown when tapping the Loop status on the Now screen while closed loop is on", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الحلقة المغلقة مفعّلة." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka je zapnutá." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop er slået til." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop ist an." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El circuito cerrado está activado." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö on päällä." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "La boucle fermée est activée." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop פועל." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A zárt hurok be van kapcsolva." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il loop chiuso è attivo." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループはオンです。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop er på." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop staat aan." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta jest włączona." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O ciclo fechado está ligado." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bucla închisă este pornită." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл включён." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka je zapnutá." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop är på." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü açık." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл увімкнено." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín đang bật." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环已开启。" + } + } + } + }, + "Closed loop off" : { + "comment" : "Reason shown for a stretch of time when Loop was in open loop because closed loop was turned off", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الحلقة المغلقة متوقفة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka vypnuta" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop slået fra" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop aus" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado desactivado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö pois" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée désactivée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop כבוי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok kikapcsolva" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso disattivato" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ オフ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop av" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop uit" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta wyłączona" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado desligado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă oprită" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл выключен" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka vypnutá" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop av" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü kapalı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл вимкнено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín tắt" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环已关闭" + } + } + } + }, + "Closed loop paused · %1$@" : { + "comment" : "Status pill on the Now screen: closed loop is switched on but paused (e.g. no CGM data), and Loop last ran this long ago. (1: duration, e.g. 3m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الحلقة المغلقة متوقفة مؤقتًا · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka pozastavena · %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop sat på pause · %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop pausiert · %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado en pausa · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö tauolla · %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée en pause · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop מושהה · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok szüneteltetve · %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso in pausa · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ一時停止中 · %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop satt på pause · %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop gepauzeerd · %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta wstrzymana · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado pausado · %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă în pauză · %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл на паузе · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka pozastavená · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop pausad · %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü duraklatıldı · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл на паузі · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín tạm dừng · %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环已暂停 · %1$@" + } + } + } + }, + "Closed loop paused · not run yet" : { + "comment" : "Status pill on the Now screen: closed loop is switched on but paused (e.g. no CGM data), and Loop has never completed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الحلقة المغلقة متوقفة مؤقتًا · لم يعمل بعد" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka pozastavena · zatím neproběhla" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop sat på pause · ikke kørt endnu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop pausiert · noch nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado en pausa · aún no se ha ejecutado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö tauolla · ei vielä ajettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée en pause · pas encore exécuté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop מושהה · טרם רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok szüneteltetve · még nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso in pausa · non ancora eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ一時停止中 · 未実行" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop satt på pause · ikke kjørt ennå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop gepauzeerd · nog niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta wstrzymana · jeszcze nie działała" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado pausado · ainda não executou" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă în pauză · nu a rulat încă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл на паузе · ещё не запускался" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka pozastavená · ešte neprebehla" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop pausad · inte körd än" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü duraklatıldı · henüz çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл на паузі · ще не запускався" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín tạm dừng · chưa chạy" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环已暂停 · 尚未运行" + } + } + } + }, + "Closed loop · %1$@" : { + "comment" : "Status pill on the Now screen: closed loop is on and Loop last ran this long ago. (1: duration, e.g. 3m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مغلقة · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka · %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö · %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok · %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ · %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop · %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado · %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă · %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop · %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín · %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环 · %1$@" + } + } + } + }, + "Closed loop · not run yet" : { + "comment" : "Status pill on the Now screen: closed loop is on but Loop has never completed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مغلقة · لم يعمل بعد" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavřená smyčka · zatím neproběhla" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · ikke kørt endnu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · noch nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito cerrado · aún no se ha ejecutado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suljettu säätö · ei vielä ajettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle fermée · pas encore exécuté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Closed Loop · טרם רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zárt hurok · még nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chiuso · non ancora eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "クローズドループ · 未実行" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukket Loop · ikke kjørt ennå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actieve loop · nog niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla zamknięta · jeszcze nie działała" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo fechado · ainda não executou" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă închisă · nu a rulat încă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутый цикл · ещё не запускался" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uzavretá slučka · ešte neprebehla" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sluten loop · inte körd än" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapalı döngü · henüz çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замкнутий цикл · ще не запускався" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp kín · chưa chạy" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "闭环 · 尚未运行" + } + } + } + }, + "COB" : { + "comment" : "Abbreviation for carbs on board (active carbohydrate) Abbreviation for carbs on board; label of a tile on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GA" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB" + } + } + } + }, + "COB (g, right)" : { + "comment" : "Chart legend: carbs on board in grams, on the right axis", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g، يمين)" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, vpravo)" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, højre)" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, rechts)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, derecha)" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, oikea)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GA (g, droite)" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, ימין)" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, jobb)" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, destra)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB(g、右)" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, høyre)" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, rechts)" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, prawa oś)" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, direita)" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, dreapta)" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (г, справа)" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, vpravo)" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, höger)" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (gr, sağ)" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (г, праворуч)" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB (g, bên phải)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "COB(克,右轴)" + } + } + } + }, + "Configuration error" : { + "comment" : "Reason Loop could not run: its settings are incomplete", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "خطأ في الإعدادات" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba konfigurace" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfigurationsfejl" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfigurationsfehler" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error de configuración" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Määritysvirhe" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur de configuration" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "שגיאת תצורה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfigurációs hiba" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Errore di configurazione" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "設定エラー" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfigurasjonsfeil" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configuratiefout" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Błąd konfiguracji" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro de configuração" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eroare de configurare" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ошибка настроек" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba konfigurácie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfigurationsfel" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yapılandırma hatası" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помилка налаштувань" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lỗi cấu hình" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "配置错误" + } + } + } + }, + "Connection error" : { + "comment" : "Reason Loop could not run: no connected devices, or a device connection failed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "خطأ في الاتصال" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba připojení" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forbindelsesfejl" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verbindungsfehler" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error de conexión" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yhteysvirhe" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur de connexion" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "שגיאת חיבור" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapcsolódási hiba" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Errore di connessione" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "接続エラー" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tilkoblingsfeil" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verbindingsfout" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Błąd połączenia" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro de conexão" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eroare de conexiune" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ошибка подключения" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba pripojenia" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anslutningsfel" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bağlantı hatası" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помилка підключення" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lỗi kết nối" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "连接错误" + } + } + } + }, + "Couldn't delete" : { + "comment" : "Alert title when deleting a Logbook entry fails", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر الحذف" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze smazat" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke slette" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Löschen fehlgeschlagen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudo eliminar" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poisto epäonnistui" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suppression impossible" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה למחוק" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült törölni" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile eliminare" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "削除できませんでした" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke slette" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verwijderen mislukt" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się usunąć" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível apagar" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-a putut șterge" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось удалить" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nedá sa odstrániť" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte ta bort" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Silinemedi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося видалити" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể xóa" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法删除" + } + } + } + }, + "Couldn't export" : { + "comment" : "Alert title when exporting the Trends PDF or CSV fails", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر التصدير" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze exportovat" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke eksportere" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Export fehlgeschlagen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudo exportar" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vienti epäonnistui" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportation impossible" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לייצא" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült exportálni" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile esportare" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "書き出せませんでした" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke eksportere" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exporteren mislukt" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się wyeksportować" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível exportar" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-a putut exporta" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось экспортировать" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nedá sa exportovať" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte exportera" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dışa aktarılamadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося експортувати" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể xuất" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法导出" + } + } + } + }, + "Couldn't load Logbook: %1$@" : { + "comment" : "Logbook error when its history can't be read. (1: system error description)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر تحميل السجل: %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze načíst deník: %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke indlæse logbogen: %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logbuch konnte nicht geladen werden: %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudo cargar el registro: %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lokikirjaa ei voitu ladata: %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossible de charger le journal : %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לטעון את היומן: %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült betölteni a naplót: %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile caricare il diario: %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ログブックを読み込めませんでした:%1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke laste inn loggboken: %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logboek kan niet worden geladen: %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się wczytać dziennika: %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível carregar o diário: %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-a putut încărca jurnalul: %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось загрузить журнал: %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denník sa nedá načítať: %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte läsa in loggboken: %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kayıt Defteri yüklenemedi: %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося завантажити журнал: %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể tải Nhật ký: %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法载入日志:%1$@" + } + } + } + }, + "Couldn't load recent CGM readings" : { + "comment" : "Prediction chart on the Now screen when recent glucose couldn't be read", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر تحميل قراءات CGM الأخيرة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze načíst nedávné hodnoty CGM" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke indlæse de seneste CGM-målinger" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktuelle CGM-Werte konnten nicht geladen werden" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudieron cargar las lecturas recientes del CGM" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Viimeisimpiä CGM-lukemia ei voitu ladata" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossible de charger les mesures CGM récentes" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לטעון קריאות CGM אחרונות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült betölteni a legutóbbi CGM-értékeket" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile caricare le letture CGM recenti" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "最近のCGM値を読み込めませんでした" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke laste inn nylige CGM-målinger" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recente CGM-waarden kunnen niet worden geladen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się wczytać ostatnich odczytów CGM" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível carregar as leituras recentes do CGM" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-au putut încărca citirile CGM recente" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось загрузить последние показания CGM" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nedajú sa načítať nedávne hodnoty CGM" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte läsa in senaste CGM-värden" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Son CGM okumaları yüklenemedi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося завантажити останні показники CGM" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể tải các chỉ số CGM gần đây" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法载入最近的 CGM 读数" + } + } + } + }, + "Couldn't load this day: %1$@" : { + "comment" : "Day page error when the day's history can't be read. (1: system error description)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر تحميل هذا اليوم: %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze načíst tento den: %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke indlæse denne dag: %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dieser Tag konnte nicht geladen werden: %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudo cargar este día: %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Päivää ei voitu ladata: %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossible de charger cette journée : %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לטעון יום זה: %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült betölteni ezt a napot: %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile caricare questo giorno: %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この日を読み込めませんでした:%1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke laste inn denne dagen: %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deze dag kan niet worden geladen: %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się wczytać tego dnia: %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível carregar este dia: %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-a putut încărca această zi: %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось загрузить этот день: %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tento deň sa nedá načítať: %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte läsa in dagen: %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu gün yüklenemedi: %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося завантажити цей день: %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể tải ngày này: %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法载入这一天:%1$@" + } + } + } + }, + "Couldn't load today's history: %1$@" : { + "comment" : "Shown on the Now screen's Today so far card when history couldn't be read. (1: system error description)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر تحميل سجل اليوم: %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze načíst dnešní historii: %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke indlæse dagens historik: %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Der heutige Verlauf konnte nicht geladen werden: %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudo cargar el historial de hoy: %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tämän päivän historiaa ei voitu ladata: %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossible de charger l'historique du jour : %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לטעון את היסטוריית היום: %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült betölteni a mai előzményeket: %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile caricare la cronologia di oggi: %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "今日の履歴を読み込めませんでした:%1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke laste inn dagens historikk: %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "De geschiedenis van vandaag kan niet worden geladen: %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się wczytać dzisiejszej historii: %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível carregar o histórico de hoje: %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-a putut încărca istoricul de azi: %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось загрузить историю за сегодня: %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnešná história sa nedá načítať: %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte läsa in dagens historik: %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bugünün geçmişi yüklenemedi: %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося завантажити історію за сьогодні: %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể tải lịch sử hôm nay: %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法载入今天的历史记录:%1$@" + } + } + } + }, + "Couldn't load Trends: %1$@" : { + "comment" : "Trends error message when the history can't be read. (1: error description)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر تحميل الاتجاهات: %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nelze načíst trendy: %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke indlæse Tendenser: %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trends konnten nicht geladen werden: %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudieron cargar las tendencias: %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendejä ei voitu ladata: %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossible de charger les tendances : %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לטעון מגמות: %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nem sikerült betölteni a trendeket: %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile caricare le tendenze: %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "トレンドを読み込めませんでした:%1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunne ikke laste inn Trender: %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trends kunnen niet worden geladen: %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się wczytać trendów: %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível carregar as tendências: %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu s-au putut încărca tendințele: %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось загрузить тренды: %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy sa nedajú načítať: %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kunde inte läsa in Trender: %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eğilimler yüklenemedi: %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося завантажити тренди: %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể tải Xu hướng: %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法载入趋势:%1$@" + } + } + } + }, + "Covers %1$@: Loop keeps 7 days of runs, and closed or open loop is recorded from when the new interface was first opened." : { + "comment" : "Trends Loop status footnote when the status covers only part of the period. (1: date range covered)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يغطي %1$@: يحتفظ Loop بسجل تشغيلات 7 أيام، وتُسجَّل الحلقة المغلقة أو المفتوحة منذ أول فتح للواجهة الجديدة." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pokrývá %1$@: Loop uchovává běhy za 7 dní a uzavřená či otevřená smyčka se zaznamenává od prvního otevření nového rozhraní." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dækker %1$@: Loop gemmer kørsler i 7 dage, og lukket eller åbent Loop registreres fra første gang den nye brugerflade blev åbnet." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Umfasst %1$@: Loop speichert Durchläufe 7 Tage lang, und Closed oder Open Loop wird erst ab dem ersten Öffnen der neuen Oberfläche aufgezeichnet." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cubre %1$@: Loop guarda 7 días de ejecuciones, y el circuito cerrado o abierto se registra desde la primera vez que se abrió la nueva interfaz." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kattaa %1$@: Loop säilyttää 7 päivän ajot, ja suljettu tai avoin säätö tallennetaan siitä lähtien, kun uusi käyttöliittymä avattiin ensimmäisen kerran." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couvre %1$@ : Loop conserve 7 jours d'exécutions, et la boucle fermée ou ouverte est enregistrée depuis la première ouverture de la nouvelle interface." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מכסה %1$@: Loop שומר 7 ימים של הרצות, ו-Closed Loop או Open Loop נרשמים מאז הפתיחה הראשונה של הממשק החדש." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lefedett időszak: %1$@. A Loop 7 napnyi futást őriz meg, a zárt vagy nyitott hurok pedig az új felület első megnyitásától kerül rögzítésre." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Copre %1$@: Loop conserva 7 giorni di esecuzioni e il loop chiuso o aperto è registrato dalla prima apertura della nuova interfaccia." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "対象期間 %1$@:Loopは実行記録を7日間保持し、クローズド/オープンループは新しいインターフェイスを初めて開いた時点から記録されます。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dekker %1$@: Loop lagrer kjøringer i 7 dager, og lukket eller åpen Loop registreres fra første gang det nye grensesnittet ble åpnet." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Omvat %1$@: Loop bewaart 7 dagen aan loop-runs, en actieve of open loop wordt vastgelegd vanaf het moment dat de nieuwe interface voor het eerst werd geopend." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obejmuje %1$@: Loop przechowuje cykle z 7 dni, a pętla zamknięta lub otwarta jest zapisywana od pierwszego otwarcia nowego interfejsu." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cobre %1$@: o Loop guarda 7 dias de execuções, e o ciclo fechado ou aberto é registrado desde a primeira vez que a nova interface foi aberta." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acoperă %1$@: Loop păstrează 7 zile de rulări, iar bucla închisă sau deschisă este înregistrată de la prima deschidere a noii interfețe." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Охвачено: %1$@. Loop хранит запуски за 7 дней, а замкнутый или открытый цикл записывается с первого открытия нового интерфейса." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pokrýva %1$@: Loop uchováva behy za 7 dní a uzavretá či otvorená slučka sa zaznamenáva od prvého otvorenia nového rozhrania." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Omfattar %1$@: Loop sparar 7 dagars körningar, och sluten eller öppen loop registreras från när det nya gränssnittet först öppnades." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapsanan dönem %1$@: Loop 7 günlük çalışma kaydı tutar; kapalı veya açık döngü, yeni arayüzün ilk açıldığı andan itibaren kaydedilir." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Охоплено: %1$@. Loop зберігає запуски за 7 днів, а замкнутий чи відкритий цикл записується з першого відкриття нового інтерфейсу." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bao gồm %1$@: Loop lưu các lần chạy trong 7 ngày, và trạng thái vòng lặp kín hoặc mở được ghi lại từ khi giao diện mới được mở lần đầu." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "覆盖 %1$@:Loop 保留 7 天的运行记录,闭环或开环状态从首次打开新界面时开始记录。" + } + } + } + }, + "CSV, one row per day" : { + "comment" : "Trends export menu item: share a CSV spreadsheet file with one row for each day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV، صف واحد لكل يوم" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, jeden řádek na den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, én række pr. dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, eine Zeile pro Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, una fila por día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, yksi rivi päivää kohden" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, une ligne par jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, שורה אחת לכל יום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, naponta egy sor" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, una riga al giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV(1日1行)" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, én rad per dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, één rij per dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, jeden wiersz na dzień" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, uma linha por dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, un rând pe zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, одна строка на день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, jeden riadok na deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, en rad per dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, gün başına bir satır" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, один рядок на день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV, mỗi ngày một dòng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "CSV,每天一行" + } + } + } + }, + "Daily pattern" : { + "comment" : "Trends card title: the ambulatory glucose profile, glucose by time of day across the period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "النمط اليومي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denní profil" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Døgnmønster" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tagesprofil" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Patrón diario" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vuorokausiprofiili" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil journalier" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "דפוס יומי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Napi mintázat" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Andamento giornaliero" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "日内パターン" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Døgnmønster" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dagpatroon" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil dobowy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Padrão diário" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipar zilnic" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Суточный профиль" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denný profil" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dygnsmönster" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük örüntü" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добовий профіль" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mẫu hằng ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日模式" + } + } + } + }, + "Daily pattern over %1$@. Median highest %2$@ at %3$@, lowest %4$@ at %5$@" : { + "comment" : "VoiceOver label for the Trends Daily pattern chart. (1: days with readings, e.g. 14 days; 2: highest median glucose; 3: time of day; 4: lowest median glucose; 5: time of day)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "النمط اليومي خلال %1$@. أعلى وسيط %2$@ عند %3$@، وأدنى وسيط %4$@ عند %5$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denní profil za %1$@. Nejvyšší medián %2$@ v %3$@, nejnižší %4$@ v %5$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Døgnmønster over %1$@. Median højest %2$@ kl. %3$@, lavest %4$@ kl. %5$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tagesprofil über %1$@. Median am höchsten %2$@ um %3$@, am niedrigsten %4$@ um %5$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Patrón diario de %1$@. Mediana más alta %2$@ a las %3$@, más baja %4$@ a las %5$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vuorokausiprofiili %1$@ ajalta. Korkein mediaani %2$@ klo %3$@, matalin %4$@ klo %5$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil journalier sur %1$@. Médiane la plus haute %2$@ à %3$@, la plus basse %4$@ à %5$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "דפוס יומי במשך %1$@. חציון גבוה ביותר %2$@ ב-%3$@, נמוך ביותר %4$@ ב-%5$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Napi mintázat, %1$@. Legmagasabb medián %2$@ ekkor: %3$@, legalacsonyabb %4$@ ekkor: %5$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Andamento giornaliero su %1$@. Mediana più alta %2$@ alle %3$@, più bassa %4$@ alle %5$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@の日内パターン。中央値の最高は%3$@の%2$@、最低は%5$@の%4$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Døgnmønster over %1$@. Median høyest %2$@ kl. %3$@, lavest %4$@ kl. %5$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dagpatroon over %1$@. Mediaan hoogst %2$@ om %3$@, laagst %4$@ om %5$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil dobowy z %1$@. Najwyższa mediana %2$@ o %3$@, najniższa %4$@ o %5$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Padrão diário em %1$@. Mediana mais alta %2$@ às %3$@, mais baixa %4$@ às %5$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipar zilnic pe %1$@. Mediana cea mai mare %2$@ la %3$@, cea mai mică %4$@ la %5$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Суточный профиль за %1$@. Наибольшая медиана %2$@ в %3$@, наименьшая %4$@ в %5$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denný profil za %1$@. Najvyšší medián %2$@ o %3$@, najnižší %4$@ o %5$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dygnsmönster över %1$@. Högsta median %2$@ kl. %3$@, lägsta %4$@ kl. %5$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ boyunca günlük örüntü. En yüksek medyan %3$@ saatinde %2$@, en düşük %5$@ saatinde %4$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добовий профіль за %1$@. Найвища медіана %2$@ о %3$@, найнижча %4$@ о %5$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mẫu hằng ngày trong %1$@. Trung vị cao nhất %2$@ lúc %3$@, thấp nhất %4$@ lúc %5$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@的每日模式。中位数最高 %2$@(%3$@),最低 %4$@(%5$@)" + } + } + } + }, + "Daily pattern: not enough days" : { + "comment" : "VoiceOver label for the Trends Daily pattern chart when fewer than 5 days have readings", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "النمط اليومي: لا توجد أيام كافية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denní profil: málo dní" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Døgnmønster: ikke nok dage" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tagesprofil: nicht genug Tage" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Patrón diario: no hay suficientes días" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vuorokausiprofiili: liian vähän päiviä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil journalier : pas assez de jours" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "דפוס יומי: אין מספיק ימים" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Napi mintázat: nincs elég nap" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Andamento giornaliero: giorni insufficienti" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "日内パターン:日数が不足しています" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Døgnmønster: ikke nok dager" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dagpatroon: niet genoeg dagen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Profil dobowy: za mało dni" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Padrão diário: dias insuficientes" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tipar zilnic: prea puține zile" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Суточный профиль: недостаточно дней" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denný profil: málo dní" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dygnsmönster: för få dagar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük örüntü: yeterli gün yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добовий профіль: замало днів" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mẫu hằng ngày: không đủ số ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日模式:天数不足" + } + } + } + }, + "Day" : { + "comment" : "Appearance option and app icon name: the light (daytime) version", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "نهار" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Päivä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "יום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nap" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "日" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dzień" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "День" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gündüz" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "День" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "日" + } + } + } + }, + "Day (Trends period)" : { + "comment" : "Trends period picker: a period of one calendar day (not daytime)", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Day" + } + }, + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يوم" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Päivä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "יום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nap" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "日" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dzień" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "День" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gün" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "День" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "日" + } + } + } + }, + "Day and Night" : { + "comment" : "Name of the app icon that follows the home screen's light or dark appearance", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "نهار وليل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Den a noc" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag og nat" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tag und Nacht" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Día y noche" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Päivä ja yö" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jour et nuit" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "יום ולילה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nap és éjszaka" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giorno e notte" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "日と夜" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag og natt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag en nacht" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dzień i noc" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dia e noite" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zi și noapte" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "День и ночь" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deň a noc" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dag och natt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gündüz ve Gece" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "День і ніч" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ngày và Đêm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "日与夜" + } + } + } + }, + "Edit" : { + "comment" : "Swipe action to edit a Logbook carb entry", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعديل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Upravit" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rediger" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bearbeiten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Muokkaa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ערוך" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Szerkesztés" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifica" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "編集" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rediger" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wijzig" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edytuj" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editați" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изменить" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Upraviť" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Redigera" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Düzenle" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Змінити" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sửa" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "编辑" + } + } + } + }, + "Edit Carb Entry" : { + "comment" : "Title of the screen for editing a carb entry from the Logbook", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعديل إدخال الكارب" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Upravit záznam sacharidů" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rediger kulhydrater" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "KH-Eintrag bearbeiten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar entrada de carbohidratos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Muokkaa hiilihydraatteja" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifier les glucides" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "עריכת פחמימות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Szénhidrát szerkesztése" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Modifica carboidrati inseriti" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "糖質の記入を編集" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rediger karbohydrater" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Koolhydraatinvoer wijzigen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edytuj wprowadzone węglowodany" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar carbs" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editați intrarea de carbohidrați" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Редактировать запись углеводов" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Upraviť záznam sacharidov" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Redigera kolhydrater" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karb Girişini Düzenle" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Редагувати запис вуглеводів" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sửa khai báo Carb" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "编辑碳水记录" + } + } + } + }, + "Eventually %1$@ %2$@" : { + "comment" : "Prediction card on the Now screen: Loop's eventual predicted glucose. (1: glucose value; 2: glucose unit, e.g. mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "في النهاية %1$@ %2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nakonec %1$@ %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Med tiden %1$@ %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voraussichtlich %1$@ %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Al final %1$@ %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennuste %1$@ %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Finalement %1$@ %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eventually %1$@ %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Várható %1$@ %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infine %1$@ %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "予想 %1$@ %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Omsider %1$@ %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uiteindelijk %1$@ %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Docelowo %1$@ %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "No final %1$@ %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "În cele din urmă %1$@ %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "В конечном итоге %1$@ %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nakoniec %1$@ %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Förväntat %1$@ %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nihai KŞ %1$@ %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Зрештою %1$@ %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kết quả %1$@ %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最终 %1$@ %2$@" + } + } + } + }, + "Export" : { + "comment" : "Trends menu title: export the period as a PDF report or CSV file", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تصدير" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportovat" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eksporter" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportieren" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportar" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vie" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exporter" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ייצוא" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportálás" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esporta" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "書き出し" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eksporter" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exporteer" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eksportuj" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportar" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportați" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Экспорт" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportovať" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exportera" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dışa Aktar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Експорт" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Xuất" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "导出" + } + } + } + }, + "From Apple Health: Loop keeps 7 days, so this day has no temp basal or schedule detail." : { + "comment" : "Day page note when the day is older than Loop's 7-day history and was read from Apple Health", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "من Apple Health: يحتفظ Loop بـ 7 أيام فقط، لذا لا توجد تفاصيل Temp Basal أو الجدول لهذا اليوم." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Z aplikace Zdraví: Loop uchovává 7 dní, takže pro tento den chybí podrobnosti o dočasném bazálu a plánu." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fra Apple Sundhed: Loop gemmer 7 dage, så denne dag har ingen detaljer om midlertidig basal eller tidsplan." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aus Apple Health: Loop speichert 7 Tage, daher gibt es für diesen Tag keine Details zu temporären Basalraten oder zum Zeitplan." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "De Apple Salud: Loop guarda 7 días, así que este día no tiene detalle de basal temporal ni de programación." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apple Terveydestä: Loop säilyttää 7 päivää, joten tältä päivältä ei ole tilapäisen basaalin tai ohjelman tietoja." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Depuis Apple Santé : Loop conserve 7 jours, donc ce jour n'a pas de détail de basal temp. ni de programmation." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מ-Apple Health: Loop שומר 7 ימים, ולכן אין ליום זה פרטי Temp Basal או תוכנית." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az Apple Egészség appból: a Loop 7 napot őriz meg, így ehhez a naphoz nincsenek ideiglenes basal- és ütemezési részletek." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Da Apple Salute: Loop conserva 7 giorni, quindi questo giorno non ha dettagli su basale temporanea o programmazione." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appleヘルスケアから取得:Loopは7日間のみ保持するため、この日には一時ベーサルやスケジュールの詳細がありません。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fra Apple Helse: Loop lagrer 7 dager, så denne dagen har ingen detaljer om midlertidig basal eller tidsplan." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uit Apple Health: Loop bewaart 7 dagen, dus deze dag heeft geen details over tijdelijk basaal of het schema." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Z aplikacji Zdrowie: Loop przechowuje 7 dni, więc dla tego dnia brak szczegółów bazy tymczasowej i harmonogramu." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do app Saúde: o Loop guarda 7 dias, então este dia não tem detalhes de basal temporária nem da programação." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Din Apple Sănătate: Loop păstrează 7 zile, așa că această zi nu are detalii despre bazala temporară sau program." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Из приложения «Здоровье»: Loop хранит 7 дней, поэтому для этого дня нет данных о временном базале и расписании." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Z aplikácie Zdravie: Loop uchováva 7 dní, preto pre tento deň chýbajú podrobnosti o dočasnom bazáli a pláne." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Från Apple Hälsa: Loop sparar 7 dagar, så den här dagen saknar detaljer om temporär basal och schema." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apple Health'ten: Loop 7 gün saklar, bu nedenle bu gün için geçici bazal veya program ayrıntısı yok." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "З програми «Здоровʼя»: Loop зберігає 7 днів, тому для цього дня немає даних про тимчасовий базал і розклад." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Từ Apple Health: Loop chỉ lưu 7 ngày, nên ngày này không có chi tiết Temp Basal hoặc lịch biểu." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "来自 Apple 健康:Loop 只保留 7 天,因此这一天没有临时基础率或预设详情。" + } + } + } + }, + "Gaps" : { + "comment" : "Trends Loop status button and screen title: list of times Loop wasn't in closed loop", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الفجوات" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Výpadky" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Huller" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lücken" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Interrupciones" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Katkot" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Interruptions" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פערים" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kimaradások" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Interruzioni" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "中断" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hull" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Onderbrekingen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Przerwy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Interrupções" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Întreruperi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пропуски" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Výpadky" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Luckor" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boşluklar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пропуски" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gián đoạn" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "中断" + } + } + } + }, + "glucose %1$@" : { + "comment" : "Logbook row detail: glucose when the dose was given. (1: glucose value, e.g. 7.5)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "السكر %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukóza %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukose %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blutzucker %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "glucosa %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukoosi %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "glycémie %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "סוכר %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "glükóz %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicemia %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖値 %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "blodsukker %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "glucose %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukoza %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicose %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicemie %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "глюкоза %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "glykémia %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukos %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "KŞ %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "глюкоза %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "đường huyết %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖 %1$@" + } + } + } + }, + "glucose %1$@ falling" : { + "comment" : "Logbook row detail: glucose when the dose was given, and falling. (1: glucose value, e.g. 11.0)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "السكر %1$@ ينخفض" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukóza %1$@, klesá" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukose %1$@ faldende" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blutzucker %1$@ fallend" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "glucosa %1$@ bajando" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukoosi %1$@ laskeva" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "glycémie %1$@ en baisse" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "סוכר %1$@ יורד" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "glükóz %1$@, csökkenő" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicemia %1$@ in discesa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖値 %1$@ 下降中" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "blodsukker %1$@ fallende" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "glucose %1$@ dalend" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukoza %1$@, spada" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicose %1$@ caindo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicemie %1$@ în scădere" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "глюкоза %1$@, падает" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "glykémia %1$@, klesá" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukos %1$@ sjunkande" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "KŞ %1$@ düşüyor" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "глюкоза %1$@, падає" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "đường huyết %1$@ đang giảm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖 %1$@ 下降中" + } + } + } + }, + "glucose %1$@ rising" : { + "comment" : "Logbook row detail: glucose when the dose was given, and rising. (1: glucose value, e.g. 11.0)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "السكر %1$@ يرتفع" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukóza %1$@, stoupá" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukose %1$@ stigende" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blutzucker %1$@ steigend" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "glucosa %1$@ subiendo" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukoosi %1$@ nouseva" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "glycémie %1$@ en hausse" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "סוכר %1$@ עולה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "glükóz %1$@, emelkedő" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicemia %1$@ in salita" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖値 %1$@ 上昇中" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "blodsukker %1$@ stigende" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "glucose %1$@ stijgend" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukoza %1$@, rośnie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicose %1$@ subindo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "glicemie %1$@ în creștere" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "глюкоза %1$@, растёт" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "glykémia %1$@, stúpa" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "glukos %1$@ stigande" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "KŞ %1$@ yükseliyor" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "глюкоза %1$@, зростає" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "đường huyết %1$@ đang tăng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖 %1$@ 上升中" + } + } + } + }, + "Glucose prediction unavailable" : { + "comment" : "VoiceOver label for the prediction chart when Loop has no prediction", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "توقع السكر غير متاح" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikce glukózy není k dispozici" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukoseforudsigelse ikke tilgængelig" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blutzuckervorhersage nicht verfügbar" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predicción de glucosa no disponible" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukoosiennuste ei saatavilla" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prédiction de glycémie indisponible" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "תחזית סוכר אינה זמינה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glükózelőrejelzés nem érhető el" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsione glicemica non disponibile" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖値の予測はありません" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blodsukkerprognose ikke tilgjengelig" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucosevoorspelling niet beschikbaar" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognoza glukozy niedostępna" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsão de glicose indisponível" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predicția glicemiei indisponibilă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз глюкозы недоступен" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikcia glykémie nie je k dispozícii" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukosprognos ej tillgänglig" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kan şekeri tahmini yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз глюкози недоступний" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dự đoán đường huyết" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖预测不可用" + } + } + } + }, + "Glucose too old" : { + "comment" : "Reason Loop could not run: the latest glucose reading was too old", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "قراءة السكر قديمة جدًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukóza je příliš stará" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukosemåling for gammel" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blutzuckerwert zu alt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucosa demasiado antigua" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukoosi liian vanha" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glycémie trop ancienne" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קריאת הסוכר ישנה מדי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Túl régi glükózérték" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glicemia troppo vecchia" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖値が古すぎます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blodsukkermåling for gammel" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucosewaarde te oud" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukoza zbyt stara" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glicose muito antiga" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glicemie prea veche" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Данные глюкозы устарели" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glykémia je príliš stará" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukosvärdet är för gammalt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kan şekeri verisi çok eski" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дані глюкози застаріли" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dữ liệu đường huyết quá cũ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "血糖数据过旧" + } + } + } + }, + "GMI" : { + "comment" : "Trends summary tile: abbreviation for Glucose Management Indicator, an estimate of HbA1c from CGM data", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "GMI" + } + } + } + }, + "Health" : { + "comment" : "Logbook carb row detail: the entry came from Apple Health", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Health" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zdraví" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sundhed" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Health" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salud" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terveys" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Santé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Health" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Egészség" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salute" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ヘルスケア" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Helse" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gezondheid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zdrowie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Saúde" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sănătate" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Здоровье" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zdravie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hälsa" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Health" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Здоровʼя" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apple Health" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "健康" + } + } + } + }, + "High" : { + "comment" : "Pill under the glucose value on the Now screen when glucose is above 250 mg/dL (13.9 mmol/L) Time in range band: glucose 181–250 mg/dL (10.1–13.9 mmol/L) Time-in-range band name: glucose 181–250 mg/dL (10.1–13.9 mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "مرتفع" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vysoká" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Høj" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoch" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alta" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Korkea" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Élevée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "גבוה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Magas" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alta" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "高値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Høy" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoog" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wysoka" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alta" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ridicată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Высокая" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vysoká" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Högt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yüksek" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Висока" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cao" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "高" + } + } + } + }, + "In range" : { + "comment" : "Time in range band: glucose 70–180 mg/dL (3.9–10.0 mmol/L) Time-in-range band name: glucose 70–180 mg/dL (3.9–10.0 mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "ضمن النطاق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "V rozsahu" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "I området" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Im Zielbereich" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "En rango" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tavoitealueella" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dans la cible" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "בטווח" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tartományban" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nell'intervallo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "範囲内" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "I målområdet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Binnen bereik" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "W zakresie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "No alvo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "În interval" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "В диапазоне" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "V rozsahu" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inom målområdet" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aralıkta" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "У діапазоні" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trong khoảng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "范围内" + } + } + } + }, + "Infusion set changed" : { + "comment" : "Pump event in the history: the infusion set was replaced", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تم تغيير مجموعة التسريب" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infuzní set vyměněn" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infusionssæt skiftet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infusionsset gewechselt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Equipo de infusión cambiado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infuusiosetti vaihdettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cathéter changé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "סט העירוי הוחלף" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infúziós szerelék cserélve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set di infusione cambiato" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "インフュージョンセット交換" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infusjonssett byttet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infuusset vervangen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wymieniono zestaw infuzyjny" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Conjunto de infusão trocado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set de infuzie schimbat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инфузионный набор заменён" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infúzny set vymenený" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Infusionsset bytt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "İnfüzyon seti değiştirildi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Інфузійний набір замінено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã thay bộ truyền" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已更换输注管路" + } + } + } + }, + "Insulin isn't being adjusted. Tap for details." : { + "comment" : "Notice detail on the Now screen when Loop hasn't completed recently", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا يتم تعديل الأنسولين. اضغط للتفاصيل." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín se neupravuje. Klepněte pro podrobnosti." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin bliver ikke justeret. Tryk for detaljer." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin wird nicht angepasst. Für Details tippen." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "La insulina no se está ajustando. Toca para ver detalles." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuliinia ei säädetä. Napauta nähdäksesi lisätiedot." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "L'insuline n'est pas ajustée. Touchez pour en savoir plus." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "האינסולין אינו מותאם. הקש לפרטים." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az inzulin nem kerül módosításra. Koppints a részletekért." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "L'insulina non viene regolata. Tocca per i dettagli." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "インスリンが調整されていません。タップして詳細を表示。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin blir ikke justert. Trykk for detaljer." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline wordt niet aangepast. Tik voor details." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina nie jest dostosowywana. Stuknij, aby zobaczyć szczegóły." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "A insulina não está sendo ajustada. Toque para ver detalhes." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina nu este ajustată. Atingeți pentru detalii." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инсулин не регулируется. Нажмите для подробностей." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín sa neupravuje. Klepnite pre podrobnosti." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulinet justeras inte. Tryck för detaljer." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "İnsülin ayarlanmıyor. Ayrıntılar için dokunun." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Інсулін не регулюється. Торкніться, щоб дізнатися більше." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin không được điều chỉnh. Chạm để xem chi tiết." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素未在调整。轻点查看详情。" + } + } + } + }, + "Insulin per day" : { + "comment" : "Trends tile and card title: average total insulin per day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الأنسولين يوميًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín za den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin pr. dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin pro Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina por día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuliini päivässä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline par jour" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אינסולין ליום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulin naponta" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina al giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日のインスリン量" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin per dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline per dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina dziennie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina por dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulină pe zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инсулин в день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín za deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin per dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük insülin" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Інсулін на день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin mỗi ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日胰岛素" + } + } + } + }, + "Insulin per day, average %1$@" : { + "comment" : "VoiceOver label for the Trends Insulin per day chart. (1: average insulin per day, e.g. 32.1 U)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الأنسولين يوميًا، المتوسط %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín za den, průměr %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin pr. dag, gennemsnit %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin pro Tag, Durchschnitt %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina por día, promedio %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuliini päivässä, keskiarvo %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline par jour, moyenne %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אינסולין ליום, ממוצע %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulin naponta, átlag %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina al giorno, media %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日のインスリン量、平均 %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin per dag, gjennomsnitt %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline per dag, gemiddeld %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina dziennie, średnio %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina por dia, média %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulină pe zi, medie %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инсулин в день, в среднем %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín za deň, priemer %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin per dag, medel %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük insülin, ortalama %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Інсулін на день, у середньому %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin mỗi ngày, trung bình %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日胰岛素,平均 %1$@" + } + } + } + }, + "Insulin per day, weekly average, average %1$@" : { + "comment" : "VoiceOver label for the Trends Insulin per day chart when bars are weekly averages. (1: average insulin per day, e.g. 32.1 U)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الأنسولين يوميًا، متوسط أسبوعي، المتوسط %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín za den, týdenní průměr, průměr %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin pr. dag, ugegennemsnit, gennemsnit %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin pro Tag, Wochendurchschnitt, Durchschnitt %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina por día, promedio semanal, promedio %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuliini päivässä, viikkokeskiarvo, keskiarvo %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline par jour, moyenne hebdomadaire, moyenne %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אינסולין ליום, ממוצע שבועי, ממוצע %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulin naponta, heti átlag, átlag %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina al giorno, media settimanale, media %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日のインスリン量、週平均、平均 %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin per dag, ukesgjennomsnitt, gjennomsnitt %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuline per dag, weekgemiddelde, gemiddeld %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina dziennie, średnia tygodniowa, średnio %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulina por dia, média semanal, média %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulină pe zi, medie săptămânală, medie %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инсулин в день, среднее за неделю, в среднем %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín za deň, týždenný priemer, priemer %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin per dag, veckomedel, medel %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Günlük insülin, haftalık ortalama, ortalama %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Інсулін на день, середнє за тиждень, у середньому %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin mỗi ngày, trung bình theo tuần, trung bình %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日胰岛素,按周平均,平均 %1$@" + } + } + } + }, + "Insulin timeline, %1$@, bolus %2$@, basal %3$@, carbs %4$@" : { + "comment" : "VoiceOver summary of the day's insulin timeline chart with no glucose readings. (1: weekday and date; 2: bolus total, e.g. 12.5 U; 3: basal total; 4: carbs total, e.g. 140 g)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "مخطط الأنسولين، %1$@، Bolus %2$@، القاعدية %3$@، الكارب %4$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Časová osa inzulínu, %1$@, bolus %2$@, bazál %3$@, sacharidy %4$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulintidslinje, %1$@, bolus %2$@, basal %3$@, kulhydrater %4$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin-Zeitleiste, %1$@, Bolus %2$@, Basal %3$@, KH %4$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cronología de insulina, %1$@, bolo %2$@, basal %3$@, carbohidratos %4$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuliinin aikajana, %1$@, bolus %2$@, basaali %3$@, hiilihydraatit %4$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chronologie de l'insuline, %1$@, bolus %2$@, basal %3$@, glucides %4$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ציר זמן אינסולין, %1$@, Bolus %2$@, Basal %3$@, פחמימות %4$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulin idővonal, %1$@, bólus %2$@, basal %3$@, szénhidrát %4$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cronologia insulina, %1$@, bolo %2$@, basale %3$@, carboidrati %4$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "インスリンのタイムライン、%1$@、ボーラス %2$@、ベーサル %3$@、カーボ %4$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulintidslinje, %1$@, bolus %2$@, basal %3$@, karbohydrater %4$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulinetijdlijn, %1$@, bolus %2$@, basaal %3$@, koolhydraten %4$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oś czasu insuliny, %1$@, bolus %2$@, baza %3$@, węglowodany %4$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Linha do tempo de insulina, %1$@, bolus %2$@, basal %3$@, carbs %4$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cronologie insulină, %1$@, bolus %2$@, bazală %3$@, carbohidrați %4$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хронология инсулина, %1$@, болюс %2$@, базал %3$@, углеводы %4$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Časová os inzulínu, %1$@, bolus %2$@, bazál %3$@, sacharidy %4$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulintidslinje, %1$@, bolus %2$@, basal %3$@, kolhydrater %4$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "İnsülin zaman çizelgesi, %1$@, bolus %2$@, bazal %3$@, karb %4$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хронологія інсуліну, %1$@, болюс %2$@, базал %3$@, вуглеводи %4$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dòng thời gian insulin, %1$@, Bolus %2$@, Basal %3$@, Carbs %4$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素时间线,%1$@,大剂量 %2$@,基础 %3$@,碳水 %4$@" + } + } + } + }, + "Insulin timeline, %1$@, bolus %2$@, basal %3$@, carbs %4$@, latest glucose %5$@ %6$@" : { + "comment" : "VoiceOver summary of the day's insulin timeline chart. (1: weekday and date; 2: bolus total, e.g. 12.5 U; 3: basal total; 4: carbs total, e.g. 140 g; 5: latest glucose value; 6: glucose unit, mmol/L or mg/dL)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "مخطط الأنسولين، %1$@، Bolus %2$@، القاعدية %3$@، الكارب %4$@، آخر قراءة سكر %5$@ %6$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Časová osa inzulínu, %1$@, bolus %2$@, bazál %3$@, sacharidy %4$@, poslední glukóza %5$@ %6$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulintidslinje, %1$@, bolus %2$@, basal %3$@, kulhydrater %4$@, seneste glukose %5$@ %6$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulin-Zeitleiste, %1$@, Bolus %2$@, Basal %3$@, KH %4$@, letzter Blutzucker %5$@ %6$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cronología de insulina, %1$@, bolo %2$@, basal %3$@, carbohidratos %4$@, última glucosa %5$@ %6$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insuliinin aikajana, %1$@, bolus %2$@, basaali %3$@, hiilihydraatit %4$@, viimeisin glukoosi %5$@ %6$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chronologie de l'insuline, %1$@, bolus %2$@, basal %3$@, glucides %4$@, dernière glycémie %5$@ %6$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ציר זמן אינסולין, %1$@, Bolus %2$@, Basal %3$@, פחמימות %4$@, סוכר אחרון %5$@ %6$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulin idővonal, %1$@, bólus %2$@, basal %3$@, szénhidrát %4$@, legutóbbi glükóz %5$@ %6$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cronologia insulina, %1$@, bolo %2$@, basale %3$@, carboidrati %4$@, ultima glicemia %5$@ %6$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "インスリンのタイムライン、%1$@、ボーラス %2$@、ベーサル %3$@、カーボ %4$@、最新の血糖値 %5$@ %6$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulintidslinje, %1$@, bolus %2$@, basal %3$@, karbohydrater %4$@, siste blodsukker %5$@ %6$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulinetijdlijn, %1$@, bolus %2$@, basaal %3$@, koolhydraten %4$@, laatste glucose %5$@ %6$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oś czasu insuliny, %1$@, bolus %2$@, baza %3$@, węglowodany %4$@, ostatnia glukoza %5$@ %6$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Linha do tempo de insulina, %1$@, bolus %2$@, basal %3$@, carbs %4$@, última glicose %5$@ %6$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cronologie insulină, %1$@, bolus %2$@, bazală %3$@, carbohidrați %4$@, ultima glicemie %5$@ %6$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хронология инсулина, %1$@, болюс %2$@, базал %3$@, углеводы %4$@, последняя глюкоза %5$@ %6$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Časová os inzulínu, %1$@, bolus %2$@, bazál %3$@, sacharidy %4$@, posledná glykémia %5$@ %6$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insulintidslinje, %1$@, bolus %2$@, basal %3$@, kolhydrater %4$@, senaste glukos %5$@ %6$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "İnsülin zaman çizelgesi, %1$@, bolus %2$@, bazal %3$@, karb %4$@, son KŞ %5$@ %6$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хронологія інсуліну, %1$@, болюс %2$@, базал %3$@, вуглеводи %4$@, остання глюкоза %5$@ %6$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dòng thời gian insulin, %1$@, Bolus %2$@, Basal %3$@, Carbs %4$@, đường huyết mới nhất %5$@ %6$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素时间线,%1$@,大剂量 %2$@,基础 %3$@,碳水 %4$@,最新血糖 %5$@ %6$@" + } + } + } + }, + "Invalid future glucose" : { + "comment" : "Reason Loop could not run: a glucose reading had a timestamp in the future", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "قراءة سكر مستقبلية غير صالحة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukóza s budoucím časem" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ugyldig glukosemåling i fremtiden" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ungültiger Blutzuckerwert in der Zukunft" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glucosa futura no válida" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Virheellinen tulevaisuuden glukoosiarvo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glycémie future non valide" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קריאת סוכר עתידית לא תקינה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Érvénytelen, jövőbeli glükózérték" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glicemia futura non valida" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "未来時刻の無効な血糖値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ugyldig blodsukkermåling i fremtiden" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ongeldige glucosewaarde in de toekomst" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glukoza z przyszłą datą" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glicose futura inválida" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glicemie invalidă, din viitor" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Глюкоза с временем в будущем" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glykémia s budúcim časom" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ogiltigt glukosvärde i framtiden" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geçersiz, ileri tarihli KŞ" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Глюкоза з часом у майбутньому" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đường huyết có thời gian trong tương lai không hợp lệ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无效的未来血糖" + } + } + } + }, + "IOB" : { + "comment" : "Abbreviation for insulin on board (active insulin) Abbreviation for insulin on board; label of a tile on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IA" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB" + } + } + } + }, + "IOB (U, left)" : { + "comment" : "Chart legend: insulin on board in units, on the left axis", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (وحدة، يسار)" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, vlevo)" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (E, venstre)" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (IE, links)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, izquierda)" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, vasen)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IA (U, gauche)" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, שמאל)" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, bal)" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, sinistra)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB(U、左)" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (E, venstre)" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (E, links)" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (J, lewa oś)" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, esquerda)" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, stânga)" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (Ед, слева)" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (j, vľavo)" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (E, vänster)" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (Ü, sol)" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, ліворуч)" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB (U, bên trái)" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "IOB(U,左轴)" + } + } + } + }, + "Last reading %1$@ ago" : { + "comment" : "Shown on the Now screen under No reading when the latest CGM reading is too old. (1: duration, e.g. 25m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "آخر قراءة قبل %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poslední hodnota před %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seneste måling for %1$@ siden" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Letzter Wert vor %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Última lectura hace %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Viimeisin lukema %1$@ sitten" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dernière mesure il y a %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קריאה אחרונה לפני %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utolsó érték %1$@ ezelőtt" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ultima lettura %1$@ fa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "最終測定 %1$@前" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Siste måling for %1$@ siden" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Laatste waarde %1$@ geleden" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostatni odczyt %1$@ temu" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Última leitura há %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ultima citire acum %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Последнее показание %1$@ назад" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Posledná hodnota pred %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senaste värde för %1$@ sedan" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Son okuma %1$@ önce" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Останній показник %1$@ тому" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chỉ số cuối cách đây %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最后读数在 %1$@前" + } + } + } + }, + "Limited" : { + "comment" : "Trends Loop status: time closed loop was on but Loop wasn't completing runs", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "محدود" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Omezeno" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Begrænset" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eingeschränkt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limitado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rajoitettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limitée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מוגבל" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Korlátozott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limitato" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "制限あり" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Begrenset" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beperkt" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ograniczona" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limitado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limitat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ограничен" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obmedzená" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Begränsad" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sınırlı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обмежено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hạn chế" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "受限" + } + } + } + }, + "Logbook" : { + "comment" : "Title of the Logbook tab Title of the Logbook tab in the redesigned interface, listing past events", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "السجل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deník" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logbog" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logbuch" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Registro" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lokikirja" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Journal" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "יומן" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Napló" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Diario" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ログブック" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loggbok" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logboek" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dziennik" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Diário" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jurnal" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Журнал" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Denník" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loggbok" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kayıt Defteri" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Журнал" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nhật ký" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "日志" + } + } + } + }, + "logged" : { + "comment" : "Logbook bolus row detail: the dose was logged by hand rather than delivered by the pump", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "مُسجَّل يدويًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "zadáno ručně" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "registreret manuelt" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "eingetragen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "registrado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "kirjattu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "saisi" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נרשם ידנית" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "naplózva" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "registrato" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "手動記録" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "registrert manuelt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "handmatig vastgelegd" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "wpisany ręcznie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "registrado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "înregistrat manual" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "внесено вручную" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "zadané ručne" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "loggad" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "elle kaydedildi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "внесено вручну" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "ghi tay" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "手动记录" + } + } + } + }, + "Loop" : { + "comment" : "Logbook filter chip: show only what Loop did automatically (Loop is the app's name) Logbook row detail: Loop made this change automatically (Loop is the app's name)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop" + } + } + } + }, + "Loop active" : { + "comment" : "Trends summary tile: share of the period Loop spent in closed loop", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop نشط" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktivní" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktiv" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktiv" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop activo" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktiivinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop actif" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop פעיל" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktív" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop attivo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop稼働" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktiv" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop actief" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktywny" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ativo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop activ" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop активен" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktívny" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktiv" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktif" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop активний" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop hoạt động" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 运行" + } + } + } + }, + "Loop can't adjust insulin without readings." : { + "comment" : "Notice detail on the Now screen under a CGM problem when there is no recent glucose reading", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا يستطيع Loop تعديل الأنسولين بدون قراءات." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nemůže upravovat inzulín bez hodnot." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kan ikke justere insulin uden målinger." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kann das Insulin ohne Messwerte nicht anpassen." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop no puede ajustar la insulina sin lecturas." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ei voi säätää insuliinia ilman lukemia." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ne peut pas ajuster l'insuline sans mesures." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop אינו יכול להתאים אינסולין ללא קריאות." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop értékek nélkül nem tudja módosítani az inzulint." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop non può regolare l'insulina senza letture." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "測定値がないとLoopはインスリンを調整できません。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kan ikke justere insulin uten målinger." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kan de insuline niet aanpassen zonder glucosewaarden." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nie może dostosowywać insuliny bez odczytów." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop não consegue ajustar a insulina sem leituras." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nu poate ajusta insulina fără citiri." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не может регулировать инсулин без показаний." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nemôže upravovať inzulín bez hodnôt." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kan inte justera insulinet utan glukosvärden." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop okuma olmadan insülini ayarlayamaz." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не може регулювати інсулін без показників." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop không thể điều chỉnh insulin khi không có chỉ số." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "没有读数,Loop 无法调整胰岛素。" + } + } + } + }, + "Loop didn't run" : { + "comment" : "Reason shown for a stretch of time when Loop did not complete a run and recorded no error", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لم يعمل Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop neproběhl" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kørte ikke" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ist nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop no se ejecutó" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ei ajanut" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ne s'est pas exécuté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop לא רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop non eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopが実行されませんでした" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kjørte ikke" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop heeft niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nie działał" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop não executou" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nu a rulat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не запускался" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop neprebehol" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kördes inte" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не запускався" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop không chạy" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 未运行" + } + } + } + }, + "Loop failed · %1$@" : { + "comment" : "Status pill on the Now screen: Loop hasn't completed for over 15 minutes. (1: duration since Loop last ran, e.g. 16m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "فشل Loop · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop selhal · %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop fejlede · %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop fehlgeschlagen · %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop falló · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop epäonnistui · %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Échec de Loop · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop נכשל · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop sikertelen · %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop non riuscito · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop失敗 · %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop feilet · %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop mislukt · %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Błąd Loop · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop falhou · %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop eșuat · %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сбой Loop · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop zlyhal · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop misslyckades · %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop başarısız · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Збій Loop · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop lỗi · %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 失败 · %1$@" + } + } + } + }, + "Loop hasn't run for %1$@" : { + "comment" : "Notice title on the Now screen when Loop hasn't completed recently. (1: duration since Loop last ran, e.g. 16m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لم يعمل Loop منذ %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop neproběhl %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har ikke kørt i %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ist seit %1$@ nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop no se ha ejecutado en %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopia ei ole ajettu %1$@ aikana" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ne s'est pas exécuté depuis %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop לא רץ כבר %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop %1$@ óta nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop non eseguito da %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopが%1$@実行されていません" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har ikke kjørt på %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop heeft %1$@ niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nie działa od %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop não executa há %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nu a rulat de %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не запускался уже %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop neprebehol %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har inte körts på %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop %1$@ süredir çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop не запускався вже %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop đã không chạy trong %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 已 %1$@未运行" + } + } + } + }, + "Loop hasn't run yet" : { + "comment" : "Title of the alert shown when tapping the Loop status on the Now screen before Loop has ever completed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لم يعمل Loop بعد" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop zatím neproběhl" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har ikke kørt endnu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ist noch nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aún no se ha ejecutado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopia ei ole vielä ajettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ne s'est pas encore exécuté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop טרם רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop még nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop non ancora eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopはまだ実行されていません" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har ikke kjørt ennå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop heeft nog niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop jeszcze nie działał" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop ainda não executou" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop nu a rulat încă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ещё не запускался" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ešte neprebehol" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop har inte körts än" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop henüz çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ще не запускався" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chưa chạy" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 尚未运行" + } + } + } + }, + "Loop keeps the last 7 days on this phone. Older doses and carbs are in Apple Health and on the Trends tab." : { + "comment" : "Logbook footer explaining why only 7 days are listed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يحتفظ Loop بآخر 7 أيام على هذا الهاتف. الجرعات والكارب الأقدم موجودة في Apple Health وفي تبويب الاتجاهات." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop uchovává posledních 7 dní v tomto telefonu. Starší dávky a sacharidy najdete v aplikaci Zdraví a na kartě Trendy." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop gemmer de seneste 7 dage på denne telefon. Ældre doser og kulhydrater findes i Apple Sundhed og på fanen Tendenser." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop speichert die letzten 7 Tage auf diesem iPhone. Ältere Dosen und KH findest Du in Apple Health und im Tab Trends." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop guarda los últimos 7 días en este teléfono. Las dosis y carbohidratos anteriores están en Apple Salud y en la pestaña Tendencias." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop säilyttää viimeiset 7 päivää tässä puhelimessa. Vanhemmat annokset ja hiilihydraatit ovat Apple Terveydessä ja Trendit-välilehdellä." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop conserve les 7 derniers jours sur ce téléphone. Les doses et glucides plus anciens sont dans Apple Santé et dans l'onglet Tendances." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop שומר את 7 הימים האחרונים בטלפון זה. מנות ופחמימות ישנות יותר נמצאות ב-Apple Health ובלשונית המגמות." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop az utolsó 7 napot őrzi meg ezen a telefonon. A régebbi adagok és szénhidrátok az Apple Egészség appban és a Trendek lapon találhatók." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop conserva gli ultimi 7 giorni su questo telefono. Dosi e carboidrati precedenti sono in Apple Salute e nella scheda Tendenze." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopはこの端末に直近7日間を保持します。それより前の投与とカーボはAppleヘルスケアとトレンドタブにあります。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop lagrer de siste 7 dagene på denne telefonen. Eldre doser og karbohydrater finner du i Apple Helse og i Trender-fanen." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop bewaart de laatste 7 dagen op deze telefoon. Oudere doses en koolhydraten vind je in Apple Health en op het tabblad Trends." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop przechowuje ostatnie 7 dni na tym telefonie. Starsze dawki i węglowodany są w aplikacji Zdrowie i na karcie Trendy." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop guarda os últimos 7 dias neste iPhone. Doses e carbs mais antigos estão no app Saúde e na aba Tendências." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop păstrează ultimele 7 zile pe acest telefon. Dozele și carbohidrații mai vechi sunt în Apple Sănătate și în fila Tendințe." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop хранит последние 7 дней на этом телефоне. Более ранние дозы и углеводы — в приложении «Здоровье» и на вкладке «Тренды»." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop uchováva posledných 7 dní v tomto telefóne. Staršie dávky a sacharidy nájdete v aplikácii Zdravie a na karte Trendy." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop sparar de senaste 7 dagarna på den här telefonen. Äldre doser och kolhydrater finns i Apple Hälsa och på fliken Trender." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop son 7 günü bu telefonda saklar. Daha eski dozlar ve karbonhidratlar Apple Health'te ve Eğilimler sekmesindedir." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop зберігає останні 7 днів на цьому телефоні. Старіші дози та вуглеводи є в програмі «Здоровʼя» і на вкладці «Тренди»." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop lưu 7 ngày gần nhất trên điện thoại này. Các liều và Carbs cũ hơn có trong Apple Health và tab Xu hướng." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 在此手机上保留最近 7 天的数据。更早的剂量和碳水可在 Apple 健康和“趋势”标签页中查看。" + } + } + } + }, + "Loop may not be giving insulin." : { + "comment" : "Notice detail on the Now screen under a critical pump problem reported by the pump", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "قد لا يقوم Loop بإعطاء الأنسولين." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop možná nepodává inzulín." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop giver muligvis ikke insulin." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop gibt möglicherweise kein Insulin ab." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Es posible que Loop no esté administrando insulina." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ei ehkä anna insuliinia." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop n'administre peut-être pas d'insuline." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ייתכן ש-Loop אינו מספק אינסולין." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lehet, hogy a Loop nem ad inzulint." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop potrebbe non erogare insulina." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopがインスリンを注入していない可能性があります。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop gir kanskje ikke insulin." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop geeft mogelijk geen insuline." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop może nie podawać insuliny." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop pode não estar entregando insulina." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Este posibil ca Loop să nu administreze insulină." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Возможно, Loop не подаёт инсулин." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop možno nepodáva inzulín." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kanske inte ger insulin." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop insülin vermiyor olabilir." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Можливо, Loop не подає інсулін." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop có thể không đang tiêm insulin." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 可能未在输注胰岛素。" + } + } + } + }, + "Loop only works out active insulin and carbs for the days it keeps" : { + "comment" : "Day page placeholder for active insulin and carbs on a day older than Loop's 7-day history", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يحسب Loop الأنسولين والكارب النشطين فقط للأيام التي يحتفظ بها" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop počítá aktivní inzulín a sacharidy jen pro dny, které uchovává" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop beregner kun aktivt insulin og kulhydrater for de dage, den gemmer" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop berechnet aktives Insulin und aktive KH nur für die gespeicherten Tage" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop solo calcula la insulina y los carbohidratos activos de los días que guarda" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop laskee aktiivisen insuliinin ja hiilihydraatit vain säilyttämilleen päiville" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop calcule l'insuline et les glucides actifs uniquement pour les jours qu'il conserve" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop מחשב אינסולין ופחמימות פעילים רק עבור הימים שהוא שומר" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop csak a megőrzött napokra számolja ki az aktív inzulint és szénhidrátot" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop calcola insulina e carboidrati attivi solo per i giorni che conserva" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopが残存インスリンと残存糖質を計算するのは、保持している日のみです" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop beregner bare aktivt insulin og karbohydrater for dagene den lagrer" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop berekent actieve insuline en koolhydraten alleen voor de dagen die het bewaart" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop oblicza aktywną insulinę i węglowodany tylko dla przechowywanych dni" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop só calcula a insulina e os carboidratos ativos dos dias que guarda" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop calculează insulina și carbohidrații activi doar pentru zilele pe care le păstrează" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop рассчитывает активный инсулин и углеводы только за хранимые дни" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop počíta aktívny inzulín a sacharidy len pre dni, ktoré uchováva" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop beräknar bara aktivt insulin och kolhydrater för de dagar som sparas" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aktif insülini ve karbı yalnızca sakladığı günler için hesaplar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop розраховує активний інсулін і вуглеводи лише за дні, які зберігає" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chỉ tính insulin và Carbs còn hoạt động cho những ngày nó lưu" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 只为其保留的日期计算活性胰岛素和碳水" + } + } + } + }, + "Loop prediction" : { + "comment" : "Chart legend on the Now screen: dashed line is Loop's predicted glucose", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "توقع Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikce Loop" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-forudsigelse" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-Vorhersage" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predicción de Loop" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopin ennuste" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prédiction de Loop" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "תחזית Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-előrejelzés" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsione di Loop" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopの予測" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-prognose" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-voorspelling" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognoza Loop" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsão do Loop" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predicție Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз Loop" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikcia Loop" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loops prognos" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop tahmini" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз Loop" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dự đoán của Loop" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 预测" + } + } + } + }, + "Loop predicts %1$@ %2$@ by %3$@" : { + "comment" : "VoiceOver summary of the prediction chart. (1: predicted glucose value; 2: glucose unit, mmol/L or mg/dL; 3: time of the prediction)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يتوقع Loop %1$@ %2$@ بحلول %3$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop predikuje %1$@ %2$@ do %3$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop forudsiger %1$@ %2$@ kl. %3$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop sagt %1$@ %2$@ bis %3$@ voraus" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop predice %1$@ %2$@ a las %3$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ennustaa %1$@ %2$@ klo %3$@ mennessä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop prévoit %1$@ %2$@ à %3$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop צופה %1$@ %2$@ עד %3$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop előrejelzése %3$@ időpontra: %1$@ %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop prevede %1$@ %2$@ alle %3$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopの予測:%3$@までに%1$@ %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop forventer %1$@ %2$@ kl. %3$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop voorspelt %1$@ %2$@ om %3$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop prognozuje %1$@ %2$@ do %3$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop prevê %1$@ %2$@ às %3$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop prezice %1$@ %2$@ până la %3$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop прогнозирует %1$@ %2$@ к %3$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop predikuje %1$@ %2$@ do %3$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop förutspår %1$@ %2$@ kl. %3$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop %3$@ itibarıyla %1$@ %2$@ tahmin ediyor" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop прогнозує %1$@ %2$@ до %3$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop dự đoán %1$@ %2$@ vào lúc %3$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 预测到 %3$@ 时为 %1$@ %2$@" + } + } + } + }, + "Loop ran at %1$@" : { + "comment" : "Title of the alert shown when tapping the Loop status on the Now screen. (1: time Loop last completed, e.g. 14:05)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "عمل Loop في %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop proběhl v %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kørte kl. %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop lief um %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop se ejecutó a las %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ajettu klo %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop exécuté à %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop רץ ב-%1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop futott: %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop eseguito alle %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop実行:%1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kjørte kl. %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop draaide om %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop działał o %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop executou às %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop a rulat la %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop запускался в %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop prebehol o %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kördes kl. %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop %1$@ saatinde çalıştı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop запускався о %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop đã chạy lúc %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 运行于 %1$@" + } + } + } + }, + "Loop runs when it has a new CGM reading and can reach the pump." : { + "comment" : "Message in the alert shown when tapping the Loop status on the Now screen before Loop has ever completed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يعمل Loop عندما تتوفر قراءة CGM جديدة ويمكنه الوصول إلى المضخة." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop běží, když má novou hodnotu z CGM a může se spojit s pumpou." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kører, når der er en ny CGM-måling, og pumpen kan nås." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop läuft, wenn ein neuer CGM-Wert vorliegt und die Pumpe erreichbar ist." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop se ejecuta cuando tiene una nueva lectura del CGM y puede comunicarse con la microinfusadora." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop ajetaan, kun uusi CGM-lukema on saatavilla ja pumppuun saadaan yhteys." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop s'exécute lorsqu'il a une nouvelle mesure CGM et peut joindre la pompe." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop רץ כאשר יש קריאת CGM חדשה והוא יכול להתחבר למשאבה." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop akkor fut, ha van új CGM-érték, és eléri a pumpát." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop viene eseguito quando ha una nuova lettura CGM e può comunicare con la pompa." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopは新しいCGM値があり、ポンプと通信できるときに実行されます。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop kjører når den har en ny CGM-måling og kan nå pumpen." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop draait zodra er een nieuwe CGM-waarde is en de pomp bereikbaar is." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop działa, gdy ma nowy odczyt CGM i może połączyć się z pompą." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O Loop executa quando tem uma nova leitura do CGM e consegue se comunicar com a bomba." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop rulează când are o citire CGM nouă și poate comunica cu pompa." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop запускается, когда есть новое показание CGM и связь с помпой." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop beží, keď má novú hodnotu z CGM a môže sa spojiť s pumpou." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop körs när det finns ett nytt CGM-värde och pumpen kan nås." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop yeni bir CGM okuması olduğunda ve pompaya ulaşabildiğinde çalışır." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop запускається, коли є новий показник CGM і звʼязок із помпою." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop chạy khi có chỉ số CGM mới và kết nối được với bơm." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "当有新的 CGM 读数且能连接胰岛素泵时,Loop 就会运行。" + } + } + } + }, + "Loop status" : { + "comment" : "Trends card title: how long Loop spent in closed loop, limited or open loop", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حالة Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stav Loop" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-status" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-Status" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estado de Loop" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopin tila" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "État de Loop" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מצב Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop állapota" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stato di Loop" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopの状態" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-status" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopstatus" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stan Loop" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Status do Loop" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Starea Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Статус Loop" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stav Loop" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopstatus" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop durumu" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стан Loop" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trạng thái Loop" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 状态" + } + } + } + }, + "Loop status is recorded from when the new interface was first opened." : { + "comment" : "Trends Loop status footnote when there is no Loop status history yet", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تُسجَّل حالة Loop منذ أول فتح للواجهة الجديدة." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stav Loop se zaznamenává od prvního otevření nového rozhraní." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-status registreres fra første gang den nye brugerflade blev åbnet." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Der Loop-Status wird ab dem ersten Öffnen der neuen Oberfläche aufgezeichnet." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El estado de Loop se registra desde la primera vez que se abrió la nueva interfaz." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopin tila tallennetaan siitä lähtien, kun uusi käyttöliittymä avattiin ensimmäisen kerran." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "L'état de Loop est enregistré depuis la première ouverture de la nouvelle interface." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מצב Loop נרשם מאז הפתיחה הראשונה של הממשק החדש." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Loop állapota az új felület első megnyitásától kerül rögzítésre." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lo stato di Loop è registrato dalla prima apertura della nuova interfaccia." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopの状態は、新しいインターフェイスを初めて開いた時点から記録されます。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-status registreres fra første gang det nye grensesnittet ble åpnet." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "De loopstatus wordt vastgelegd vanaf het moment dat de nieuwe interface voor het eerst werd geopend." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stan Loop jest zapisywany od pierwszego otwarcia nowego interfejsu." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "O status do Loop é registrado desde a primeira vez que a nova interface foi aberta." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Starea Loop este înregistrată de la prima deschidere a noii interfețe." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Статус Loop записывается с первого открытия нового интерфейса." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stav Loop sa zaznamenáva od prvého otvorenia nového rozhrania." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopstatus registreras från när det nya gränssnittet först öppnades." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop durumu, yeni arayüzün ilk açıldığı andan itibaren kaydedilir." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стан Loop записується з першого відкриття нового інтерфейсу." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trạng thái Loop được ghi lại từ khi giao diện mới được mở lần đầu." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 状态从首次打开新界面时开始记录。" + } + } + } + }, + "Loop trends" : { + "comment" : "Title of the exported Trends PDF report", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اتجاهات Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy Loop" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-tendenser" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-Trends" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendencias de Loop" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trendit" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendances Loop" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מגמות Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trendek" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendenze Loop" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopトレンド" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trender" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trends" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy Loop" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendências do Loop" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendințe Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренды Loop" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy Loop" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trender" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop eğilimleri" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренди Loop" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Xu hướng Loop" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 趋势" + } + } + } + }, + "Loop trends %1$@" : { + "comment" : "File name of an exported Trends report or CSV, without the extension. (1: date range of the period)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اتجاهات Loop %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy Loop %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-tendenser %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-Trends %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendencias de Loop %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trendit %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendances Loop %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מגמות Loop %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trendek %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendenze Loop %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopトレンド %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trender %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trends %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy Loop %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendências do Loop %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendințe Loop %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренды Loop %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy Loop %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop-trender %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop eğilimleri %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренди Loop %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Xu hướng Loop %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop 趋势 %1$@" + } + } + } + }, + "Loop · %lld changes · tap to list" : { + "comment" : "Logbook basal adjustments row subtitle: how many temp basals Loop set in the day; tapping lists them. (1: number of changes)", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld change · tap to list" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld changes · tap to list" + } + } + } + } + }, + "ar" : { + "variations" : { + "plural" : { + "zero" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld تغيير · اضغط للعرض" + } + }, + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld تغيير · اضغط للعرض" + } + }, + "two" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld تغيير · اضغط للعرض" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld تغييرات · اضغط للعرض" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld تغييرًا · اضغط للعرض" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld تغيير · اضغط للعرض" + } + } + } + } + }, + "cs" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld změna · klepněte pro seznam" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld změny · klepněte pro seznam" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld změny · klepněte pro seznam" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld změn · klepněte pro seznam" + } + } + } + } + }, + "da" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld ændring · tryk for liste" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld ændringer · tryk for liste" + } + } + } + } + }, + "de" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld Änderung · tippen für Liste" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld Änderungen · tippen für Liste" + } + } + } + } + }, + "es" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld cambio · toca para ver" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld cambios · toca para ver" + } + } + } + } + }, + "fi" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld muutos · näytä napauttamalla" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld muutosta · näytä napauttamalla" + } + } + } + } + }, + "fr" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modification · touchez pour la liste" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modifications · touchez pour la liste" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modifications · touchez pour la liste" + } + } + } + } + }, + "he" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld שינוי · הקש לרשימה" + } + }, + "two" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld שינויים · הקש לרשימה" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld שינויים · הקש לרשימה" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld שינויים · הקש לרשימה" + } + } + } + } + }, + "hu" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld módosítás · koppints a listához" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld módosítás · koppints a listához" + } + } + } + } + }, + "it" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modifica · tocca per l'elenco" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modifiche · tocca per l'elenco" + } + } + } + } + }, + "ja" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld件の変更 · タップで一覧表示" + } + } + } + } + }, + "nb" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld endring · trykk for liste" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld endringer · trykk for liste" + } + } + } + } + }, + "nl" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld wijziging · tik voor lijst" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld wijzigingen · tik voor lijst" + } + } + } + } + }, + "pl" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmiana · stuknij, aby wyświetlić" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmiany · stuknij, aby wyświetlić" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmian · stuknij, aby wyświetlić" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmiany · stuknij, aby wyświetlić" + } + } + } + } + }, + "pt-BR" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld alteração · toque para listar" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld alterações · toque para listar" + } + } + } + } + }, + "ro" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modificare · atingeți pentru listă" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld modificări · atingeți pentru listă" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld de modificări · atingeți pentru listă" + } + } + } + } + }, + "ru" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld изменение · нажмите для списка" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld изменения · нажмите для списка" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld изменений · нажмите для списка" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld изменения · нажмите для списка" + } + } + } + } + }, + "sk" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmena · klepnite pre zoznam" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmeny · klepnite pre zoznam" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmeny · klepnite pre zoznam" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld zmien · klepnite pre zoznam" + } + } + } + } + }, + "sv" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld ändring · tryck för lista" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld ändringar · tryck för lista" + } + } + } + } + }, + "tr" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld değişiklik · listelemek için dokunun" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld değişiklik · listelemek için dokunun" + } + } + } + } + }, + "uk" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld зміна · торкніться для списку" + } + }, + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld зміни · торкніться для списку" + } + }, + "many" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld змін · торкніться для списку" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld зміни · торкніться для списку" + } + } + } + } + }, + "vi" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld thay đổi · chạm để xem danh sách" + } + } + } + } + }, + "zh-Hans" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop · %lld次更改 · 轻点查看列表" + } + } + } + } + } + } + }, + "Low" : { + "comment" : "Pill under the glucose value on the Now screen when glucose is below 70 mg/dL (3.9 mmol/L) Time in range band: glucose 54–69 mg/dL (3.0–3.8 mmol/L) Time-in-range band name: glucose 54–69 mg/dL (3.0–3.8 mmol/L)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "منخفض" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nízká" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lav" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niedrig" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baja" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Matala" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basse" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נמוך" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alacsony" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bassa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "低値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lav" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Laag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niska" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baixa" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scăzută" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Низкая" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nízka" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lågt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Düşük" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Низька" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thấp" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "低" + } + } + } + }, + "Manual" : { + "comment" : "Logbook row detail: the user made this entry or change by hand", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يدوي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ručně" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuell" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuaalinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ידני" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kézi" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "手動" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuell" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Handmatig" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ręcznie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вручную" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ručne" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuell" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вручну" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thủ công" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "手动" + } + } + } + }, + "Manual · %1$@" : { + "comment" : "Logbook temp basal row subtitle: set by hand, then the rate and how long. (1: description, e.g. 0.50 U/h for 30m (scheduled 0.80))", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يدوي · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ručně · %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel · %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuell · %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuaalinen · %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ידני · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kézi · %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuale · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "手動 · %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuell · %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Handmatig · %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ręcznie · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual · %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manual · %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вручную · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ručne · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuell · %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manuel · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вручну · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thủ công · %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "手动 · %1$@" + } + } + } + }, + "Median" : { + "comment" : "Trends Daily pattern legend: the median glucose line", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الوسيط" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medián" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Median" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Median" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediana" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediaani" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Médiane" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "חציון" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medián" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediana" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "中央値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Median" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediaan" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediana" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediana" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mediană" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Медиана" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medián" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Median" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Medyan" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Медіана" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trung vị" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "中位数" + } + } + } + }, + "Missing data error" : { + "comment" : "Reason Loop could not run: data it needs was missing", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "خطأ بيانات مفقودة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba chybějících dat" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fejl: manglende data" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fehler: fehlende Daten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error de datos faltantes" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tietoja puuttuu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur de données manquantes" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "שגיאת נתונים חסרים" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hiányzó adat" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Errore dati mancanti" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "データ欠落エラー" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Feil: manglende data" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fout: ontbrekende gegevens" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Błąd brakujących danych" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro de dados ausentes" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eroare: date lipsă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ошибка: нет данных" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba chýbajúcich údajov" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data saknas" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eksik veri hatası" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помилка: немає даних" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lỗi thiếu dữ liệu" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "数据缺失错误" + } + } + } + }, + "Needs 10 days of CGM" : { + "comment" : "Trends GMI tile detail when fewer than 10 days of CGM data are available", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يحتاج إلى 10 أيام من CGM" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vyžaduje 10 dní CGM" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kræver 10 dages CGM" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Benötigt 10 Tage CGM" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requiere 10 días de CGM" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vaatii 10 päivää CGM-dataa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nécessite 10 jours de CGM" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נדרשים 10 ימי CGM" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "10 nap CGM-adat szükséges" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Servono 10 giorni di CGM" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGMデータが10日分必要" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Krever 10 dager med CGM" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vereist 10 dagen CGM" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wymaga 10 dni CGM" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requer 10 dias de CGM" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Necesită 10 zile de CGM" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нужно 10 дней CGM" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vyžaduje 10 dní CGM" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kräver 10 dagars CGM" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "10 günlük CGM gerekir" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Потрібно 10 днів CGM" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cần 10 ngày dữ liệu CGM" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "需要 10 天 CGM 数据" + } + } + } + }, + "New Interface" : { + "comment" : "Title of the toggle for the redesigned interface", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الواجهة الجديدة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nové rozhraní" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ny brugerflade" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neue Oberfläche" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nueva interfaz" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uusi käyttöliittymä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nouvelle interface" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ממשק חדש" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Új felület" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nuova interfaccia" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "新しいインターフェイス" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nytt grensesnitt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nieuwe interface" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nowy interfejs" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nova interface" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Interfață nouă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Новый интерфейс" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nové rozhranie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nytt gränssnitt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yeni Arayüz" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Новий інтерфейс" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giao diện mới" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "新界面" + } + } + } + }, + "Next 3 hours" : { + "comment" : "Title of the prediction chart card on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الساعات الثلاث القادمة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Příští 3 hodiny" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Næste 3 timer" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nächste 3 Stunden" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Próximas 3 horas" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seuraavat 3 tuntia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "3 prochaines heures" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "3 השעות הבאות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Következő 3 óra" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prossime 3 ore" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "今後3時間" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neste 3 timer" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Komende 3 uur" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Następne 3 godziny" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Próximas 3 horas" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Următoarele 3 ore" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ближайшие 3 часа" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nasledujúce 3 hodiny" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kommande 3 timmar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sonraki 3 saat" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Наступні 3 години" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "3 giờ tới" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "未来 3 小时" + } + } + } + }, + "Next day" : { + "comment" : "Accessibility label for the day page button that steps forward a day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اليوم التالي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Další den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Næste dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nächster Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Día siguiente" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seuraava päivä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jour suivant" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "היום הבא" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Következő nap" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giorno successivo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "翌日" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neste dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Volgende dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Następny dzień" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Próximo dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ziua următoare" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Следующий день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ďalší deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nästa dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sonraki gün" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Наступний день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ngày sau" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "后一天" + } + } + } + }, + "Next period" : { + "comment" : "VoiceOver label for the Trends button that moves forward one period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الفترة التالية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Další období" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Næste periode" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nächster Zeitraum" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Período siguiente" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seuraava jakso" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Période suivante" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "התקופה הבאה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Következő időszak" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Periodo successivo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "次の期間" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Neste periode" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Volgende periode" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Następny okres" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Próximo período" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Perioada următoare" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Следующий период" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ďalšie obdobie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nästa period" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sonraki dönem" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Наступний період" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Khoảng thời gian sau" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "下一时段" + } + } + } + }, + "Night" : { + "comment" : "Appearance option that always uses dark mode Name of the dark app icon", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "ليل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noc" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nat" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nacht" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noche" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yö" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nuit" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לילה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Éjszaka" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notte" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "夜" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Natt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nacht" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noc" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noite" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noapte" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ночь" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noc" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Natt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gece" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ніч" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đêm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "夜" + } + } + } + }, + "No active insulin or carbs on this day" : { + "comment" : "Day page placeholder when there was no insulin or carbs on board all day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا يوجد أنسولين أو كارب نشط في هذا اليوم" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "V tento den nebyl žádný aktivní inzulín ani sacharidy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intet aktivt insulin eller kulhydrater denne dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kein aktives Insulin und keine aktiven KH an diesem Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin insulina ni carbohidratos activos este día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei aktiivista insuliinia tai hiilihydraatteja tänä päivänä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune insuline ni glucides actifs ce jour-là" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין אינסולין או פחמימות פעילים ביום זה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ezen a napon nem volt aktív inzulin vagy szénhidrát" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna insulina o carboidrati attivi in questo giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この日は残存インスリンも残存糖質もありません" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen aktivt insulin eller karbohydrater denne dagen" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen actieve insuline of koolhydraten op deze dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak aktywnej insuliny i węglowodanów tego dnia" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem insulina ou carboidratos ativos neste dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără insulină sau carbohidrați activi în această zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "В этот день не было активного инсулина или углеводов" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "V tento deň nebol žiadny aktívny inzulín ani sacharidy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget aktivt insulin eller kolhydrater denna dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu gün aktif insülin veya karb yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Цього дня не було активного інсуліну чи вуглеводів" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có insulin hoặc Carbs còn hoạt động trong ngày này" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "这一天没有活性胰岛素或碳水" + } + } + } + }, + "No CGM data" : { + "comment" : "Trends Average tile detail when the period has no glucose readings", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná data CGM" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine CGM-Daten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin datos del CGM" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei CGM-dataa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין נתוני CGM" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs CGM-adat" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun dato CGM" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGMデータなし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen CGM-gegevens" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak danych CGM" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem dados do CGM" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără date CGM" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет данных CGM" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne údaje CGM" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM verisi yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає даних CGM" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dữ liệu CGM" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无 CGM 数据" + } + } + } + }, + "No CGM data %1$@ – %2$@" : { + "comment" : "Chart note: a gap in glucose readings. (1: start time; 2: end time)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM %1$@ – %2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná data CGM %1$@ – %2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data %1$@ – %2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine CGM-Daten %1$@ – %2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin datos del CGM %1$@ – %2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei CGM-dataa %1$@ – %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM %1$@ – %2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין נתוני CGM %1$@ – %2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs CGM-adat %1$@ – %2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun dato CGM %1$@ – %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGMデータなし %1$@ – %2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data %1$@ – %2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen CGM-gegevens %1$@ – %2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak danych CGM %1$@ – %2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem dados do CGM %1$@ – %2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără date CGM %1$@ – %2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет данных CGM %1$@ – %2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne údaje CGM %1$@ – %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data %1$@ – %2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM verisi yok %1$@ – %2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає даних CGM %1$@ – %2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dữ liệu CGM %1$@ – %2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无 CGM 数据 %1$@ – %2$@" + } + } + } + }, + "No CGM data %1$@ – %2$@ and %3$@" : { + "comment" : "Chart note: the longest gap in glucose readings, plus the shorter ones. (1: start time; 2: end time; 3: number of shorter gaps, e.g. 2 shorter gaps)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM %1$@ – %2$@ و %3$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná data CGM %1$@ – %2$@ a %3$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data %1$@ – %2$@ og %3$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine CGM-Daten %1$@ – %2$@ und %3$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin datos del CGM %1$@ – %2$@ y %3$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei CGM-dataa %1$@ – %2$@ ja %3$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM %1$@ – %2$@ et %3$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין נתוני CGM %1$@ – %2$@ ו-%3$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs CGM-adat %1$@ – %2$@, és %3$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun dato CGM %1$@ – %2$@ e %3$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGMデータなし %1$@ – %2$@(%3$@)" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data %1$@ – %2$@ og %3$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen CGM-gegevens %1$@ – %2$@ en %3$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak danych CGM %1$@ – %2$@ oraz %3$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem dados do CGM %1$@ – %2$@ e %3$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără date CGM %1$@ – %2$@ și %3$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет данных CGM %1$@ – %2$@ и ещё %3$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne údaje CGM %1$@ – %2$@ a %3$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data %1$@ – %2$@ och %3$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM verisi yok %1$@ – %2$@ ve %3$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає даних CGM %1$@ – %2$@ і ще %3$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dữ liệu CGM %1$@ – %2$@ và %3$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无 CGM 数据 %1$@ – %2$@,%3$@" + } + } + } + }, + "No CGM data in the last 3 hours" : { + "comment" : "Empty prediction chart on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM في آخر 3 ساعات" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná data CGM za poslední 3 hodiny" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data de seneste 3 timer" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine CGM-Daten in den letzten 3 Stunden" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin datos del CGM en las últimas 3 horas" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei CGM-dataa viimeisen 3 tunnin aikana" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM ces 3 dernières heures" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין נתוני CGM ב-3 השעות האחרונות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs CGM-adat az elmúlt 3 órában" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun dato CGM nelle ultime 3 ore" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "過去3時間のCGMデータなし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data de siste 3 timene" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen CGM-gegevens in de afgelopen 3 uur" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak danych CGM z ostatnich 3 godzin" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem dados do CGM nas últimas 3 horas" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără date CGM în ultimele 3 ore" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет данных CGM за последние 3 часа" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne údaje CGM za posledné 3 hodiny" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data de senaste 3 timmarna" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Son 3 saatte CGM verisi yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає даних CGM за останні 3 години" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dữ liệu CGM trong 3 giờ qua" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "过去 3 小时无 CGM 数据" + } + } + } + }, + "No CGM data in this period" : { + "comment" : "Trends chart placeholder when the period has no glucose readings", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM في هذه الفترة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná data CGM v tomto období" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data i denne periode" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine CGM-Daten in diesem Zeitraum" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin datos del CGM en este período" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei CGM-dataa tällä jaksolla" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM sur cette période" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין נתוני CGM בתקופה זו" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs CGM-adat ebben az időszakban" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun dato CGM in questo periodo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この期間のCGMデータなし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data i denne perioden" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen CGM-gegevens in deze periode" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak danych CGM w tym okresie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem dados do CGM neste período" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără date CGM în această perioadă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет данных CGM за этот период" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne údaje CGM v tomto období" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data under denna period" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu dönemde CGM verisi yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає даних CGM за цей період" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dữ liệu CGM trong khoảng thời gian này" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "此时段无 CGM 数据" + } + } + } + }, + "No CGM data on this day" : { + "comment" : "Chart note: there are no glucose readings for the whole day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM في هذا اليوم" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná data CGM v tento den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data denne dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine CGM-Daten an diesem Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin datos del CGM este día" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei CGM-dataa tänä päivänä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM ce jour-là" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין נתוני CGM ביום זה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs CGM-adat ezen a napon" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessun dato CGM in questo giorno" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この日のCGMデータなし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data denne dagen" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen CGM-gegevens op deze dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak danych CGM tego dnia" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem dados do CGM neste dia" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără date CGM în această zi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет данных CGM за этот день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne údaje CGM v tento deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data denna dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu günde CGM verisi yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає даних CGM за цей день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có dữ liệu CGM trong ngày này" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "这一天无 CGM 数据" + } + } + } + }, + "No CGM data yet today" : { + "comment" : "Chart note: there are no glucose readings so far today", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد بيانات CGM اليوم حتى الآن" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes zatím žádná data CGM" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data endnu i dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Heute noch keine CGM-Daten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aún no hay datos del CGM hoy" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei vielä CGM-dataa tänään" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune donnée CGM aujourd'hui pour l'instant" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין עדיין נתוני CGM היום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ma még nincs CGM-adat" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ancora nessun dato CGM oggi" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "今日はまだCGMデータなし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen CGM-data ennå i dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vandaag nog geen CGM-gegevens" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dziś jeszcze brak danych CGM" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ainda sem dados do CGM hoje" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Încă nu există date CGM azi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сегодня пока нет данных CGM" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes zatiaľ žiadne údaje CGM" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga CGM-data än i dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bugün henüz CGM verisi yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сьогодні ще немає даних CGM" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hôm nay chưa có dữ liệu CGM" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "今天尚无 CGM 数据" + } + } + } + }, + "No gaps: Loop ran closed loop all through this period." : { + "comment" : "Trends Gaps list when Loop was in closed loop for the whole period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا فجوات: عمل Loop بالحلقة المغلقة طوال هذه الفترة." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádné výpadky: Loop běžel v uzavřené smyčce celé období." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen huller: Loop kørte lukket Loop i hele perioden." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Lücken: Loop lief im gesamten Zeitraum im Closed Loop." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin interrupciones: Loop funcionó en circuito cerrado durante todo el período." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei katkoja: Loop toimi suljetulla säädöllä koko jakson ajan." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune interruption : Loop est resté en boucle fermée toute la période." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין פערים: Loop פעל ב-Closed Loop לאורך כל התקופה." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs kimaradás: a Loop az egész időszakban zárt hurokban futott." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna interruzione: Loop è rimasto in loop chiuso per tutto il periodo." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "中断なし:この期間中、Loopは常にクローズドループで動作しました。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen hull: Loop kjørte lukket Loop gjennom hele perioden." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen onderbrekingen: Loop draaide de hele periode in actieve loop." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak przerw: Loop działał w pętli zamkniętej przez cały okres." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem interrupções: o Loop ficou em ciclo fechado durante todo o período." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fără întreruperi: Loop a rulat în buclă închisă toată perioada." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пропусков нет: Loop работал в замкнутом цикле весь период." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne výpadky: Loop bežal v uzavretej slučke celé obdobie." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga luckor: Loop körde sluten loop under hela perioden." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boşluk yok: Loop bu dönem boyunca kapalı döngüde çalıştı." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пропусків немає: Loop працював у замкнутому циклі весь період." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không gián đoạn: Loop chạy vòng lặp kín suốt khoảng thời gian này." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无中断:此时段内 Loop 一直以闭环运行。" + } + } + } + }, + "No insulin recorded in this period" : { + "comment" : "Trends Insulin per day chart placeholder when no insulin was delivered in the period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لم يُسجَّل أنسولين في هذه الفترة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "V tomto období nebyl zaznamenán žádný inzulín" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intet insulin registreret i denne periode" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kein Insulin in diesem Zeitraum erfasst" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se registró insulina en este período" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei kirjattua insuliinia tällä jaksolla" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune insuline enregistrée sur cette période" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא נרשם אינסולין בתקופה זו" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs rögzített inzulin ebben az időszakban" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna insulina registrata in questo periodo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この期間のインスリン記録なし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen insulin registrert i denne perioden" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen insuline vastgelegd in deze periode" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak zapisanej insuliny w tym okresie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhuma insulina registrada neste período" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nicio insulină înregistrată în această perioadă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "За этот период инсулин не записан" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "V tomto období nebol zaznamenaný žiadny inzulín" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget insulin registrerat under denna period" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu dönemde kaydedilmiş insülin yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "За цей період інсулін не записано" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có insulin được ghi lại trong khoảng thời gian này" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "此时段内无胰岛素记录" + } + } + } + }, + "No loop runs kept" : { + "comment" : "Trends Loop active tile detail when no Loop run history is available for the period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد تشغيلات Loop محفوظة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádné uložené běhy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen Loop-kørsler gemt" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Loop-Durchläufe gespeichert" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se guardaron ejecuciones de Loop" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei tallennettuja Loop-ajoja" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune exécution de Loop conservée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא נשמרו הרצות Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs megőrzött Loop-futás" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna esecuzione di Loop conservata" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop実行記録なし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen Loop-kjøringer lagret" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen loop-runs bewaard" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak zapisanych cykli" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhuma execução do Loop guardada" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu sunt păstrate rulări Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет сохранённых запусков" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadne uložené behy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga loopkörningar sparade" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Saklanan Loop çalışması yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає збережених запусків" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không lưu lần chạy Loop nào" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无 Loop 运行记录" + } + } + } + }, + "No loop runs recorded in this period" : { + "comment" : "Trends Loop status placeholder when there is no Loop run history for the period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لم تُسجَّل تشغيلات Loop في هذه الفترة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "V tomto období nebyly zaznamenány žádné běhy Loop" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen Loop-kørsler registreret i denne periode" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Loop-Durchläufe in diesem Zeitraum erfasst" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se registraron ejecuciones de Loop en este período" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei Loop-ajoja tällä jaksolla" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune exécution de Loop enregistrée sur cette période" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא נרשמו הרצות Loop בתקופה זו" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs rögzített Loop-futás ebben az időszakban" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna esecuzione di Loop registrata in questo periodo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "この期間のLoop実行記録なし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen Loop-kjøringer registrert i denne perioden" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen loop-runs vastgelegd in deze periode" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak zapisanych cykli Loop w tym okresie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nenhuma execução do Loop registrada neste período" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nicio rulare Loop înregistrată în această perioadă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "За этот период запуски Loop не записаны" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "V tomto období neboli zaznamenané žiadne behy Loop" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inga loopkörningar registrerade under denna period" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu dönemde kaydedilmiş Loop çalışması yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "За цей період запуски Loop не записано" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có lần chạy Loop nào được ghi lại trong khoảng thời gian này" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "此时段内无 Loop 运行记录" + } + } + } + }, + "No reading" : { + "comment" : "Shown on the Now screen in place of the glucose value when there is no recent CGM reading", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا توجد قراءة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žádná hodnota" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen måling" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kein Wert" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin lectura" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei lukemaa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune mesure" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין קריאה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs érték" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna lettura" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "測定値なし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingen måling" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geen waarde" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak odczytu" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem leitura" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nicio citire" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет показаний" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Žiadna hodnota" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget värde" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Okuma yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає показників" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có chỉ số" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无读数" + } + } + } + }, + "Not enough days for a pattern: %1$@ of 5" : { + "comment" : "Trends Daily pattern footnote when fewer than 5 days have readings; the chart shows raw readings instead. (1: days with readings)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "أيام غير كافية لنمط: %1$@ من 5" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Málo dní pro profil: %1$@ z 5" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikke nok dage til et mønster: %1$@ af 5" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nicht genug Tage für ein Profil: %1$@ von 5" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No hay suficientes días para un patrón: %1$@ de 5" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Liian vähän päiviä profiiliin: %1$@ / 5" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pas assez de jours pour un profil : %1$@ sur 5" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין מספיק ימים לדפוס: %1$@ מתוך 5" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs elég nap a mintázathoz: %1$@ / 5" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giorni insufficienti per un andamento: %1$@ su 5" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "パターン作成には日数不足:%1$@ / 5日" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikke nok dager for et mønster: %1$@ av 5" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niet genoeg dagen voor een patroon: %1$@ van 5" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Za mało dni na profil: %1$@ z 5" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dias insuficientes para um padrão: %1$@ de 5" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prea puține zile pentru un tipar: %1$@ din 5" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мало дней для профиля: %1$@ из 5" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Málo dní pre profil: %1$@ z 5" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "För få dagar för ett mönster: %1$@ av 5" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Örüntü için yeterli gün yok: %1$@ / 5" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замало днів для профілю: %1$@ з 5" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không đủ ngày để tạo mẫu: %1$@ / 5" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "天数不足以生成模式:%1$@ / 5" + } + } + } + }, + "Nothing logged" : { + "comment" : "Logbook day with no entries", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا شيء مسجَّل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nic zaznamenáno" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intet registreret" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nichts eingetragen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nada registrado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei kirjauksia" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune saisie" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא נרשם דבר" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs bejegyzés" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna registrazione" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "記録なし" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingenting registrert" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niets vastgelegd" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak wpisów" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nada registrado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nimic înregistrat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет записей" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nič zaznamenané" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget loggat" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kayıt yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає записів" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có ghi chép" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无记录" + } + } + } + }, + "Nothing logged in the last 7 days." : { + "comment" : "Logbook empty state when there are no entries at all", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا شيء مسجَّل في آخر 7 أيام." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Za posledních 7 dní nic zaznamenáno." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intet registreret de seneste 7 dage." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "In den letzten 7 Tagen nichts eingetragen." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nada registrado en los últimos 7 días." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei kirjauksia viimeisen 7 päivän aikana." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aucune saisie ces 7 derniers jours." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא נרשם דבר ב-7 הימים האחרונים." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs bejegyzés az elmúlt 7 napban." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nessuna registrazione negli ultimi 7 giorni." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "過去7日間の記録はありません。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingenting registrert de siste 7 dagene." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niets vastgelegd in de afgelopen 7 dagen." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak wpisów z ostatnich 7 dni." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nada registrado nos últimos 7 dias." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nimic înregistrat în ultimele 7 zile." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет записей за последние 7 дней." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Za posledných 7 dní nič zaznamenané." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget loggat de senaste 7 dagarna." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Son 7 günde kayıt yok." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає записів за останні 7 днів." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có ghi chép nào trong 7 ngày qua." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "过去 7 天没有记录。" + } + } + } + }, + "Nothing to show for this filter" : { + "comment" : "Logbook day with no entries matching the selected filter", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "لا شيء لعرضه لهذا الفلتر" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pro tento filtr nic k zobrazení" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Intet at vise for dette filter" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keine Einträge für diesen Filter" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nada que mostrar con este filtro" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ei näytettävää tällä suodattimella" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rien à afficher pour ce filtre" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אין מה להציג עבור מסנן זה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nincs megjeleníthető elem ehhez a szűrőhöz" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niente da mostrare per questo filtro" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "このフィルタに該当する項目はありません" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingenting å vise for dette filteret" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Niets te tonen voor dit filter" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brak wpisów dla tego filtra" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nada para mostrar neste filtro" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nimic de afișat pentru acest filtru" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нет записей для этого фильтра" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre tento filter nič na zobrazenie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inget att visa för detta filter" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bu filtre için gösterilecek bir şey yok" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Немає записів для цього фільтра" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có mục nào cho bộ lọc này" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "此筛选条件下没有内容" + } + } + } + }, + "Now" : { + "comment" : "Title at the top of the Now screen, showing current glucose and Loop status Title of the Now tab in the redesigned interface, showing current glucose and Loop status", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الآن" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nyní" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jetzt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ahora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nyt" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Maintenant" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "עכשיו" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Most" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ora" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "現在" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teraz" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agora" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acum" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сейчас" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teraz" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nu" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Şimdi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Зараз" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hiện tại" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "当前" + } + } + } + }, + "now" : { + "comment" : "Prediction chart x-axis label marking the current time", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الآن" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "nyní" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "nu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "jetzt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "ahora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "nyt" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "maint." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "עכשיו" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "most" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "ora" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "現在" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "nå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "nu" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "teraz" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "agora" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "acum" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "сейчас" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "teraz" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "nu" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "şimdi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "зараз" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "bây giờ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "现在" + } + } + } + }, + "Open loop / manual" : { + "comment" : "Trends Loop status: time closed loop was switched off", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مفتوحة / يدوي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevřená smyčka / ručně" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbent Loop / manuel" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Loop / manuell" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito abierto / manual" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avoin säätö / manuaalinen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle ouverte / manuel" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Loop / ידני" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nyitott hurok / kézi" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aperto / manuale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "オープンループ/手動" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpen Loop / manuell" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open loop / handmatig" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla otwarta / ręcznie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo aberto / manual" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă deschisă / manual" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открытый цикл / вручную" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorená slučka / ručne" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppen loop / manuell" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Açık döngü / manuel" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкритий цикл / вручну" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp mở / thủ công" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "开环 / 手动" + } + } + } + }, + "Open loop · %1$@" : { + "comment" : "Status pill on the Now screen: closed loop is off (Loop recommends only) and Loop last ran this long ago. (1: duration, e.g. 3m)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مفتوحة · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevřená smyčka · %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbent Loop · %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Loop · %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito abierto · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avoin säätö · %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle ouverte · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Loop · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nyitott hurok · %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aperto · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "オープンループ · %1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpen Loop · %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open loop · %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla otwarta · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo aberto · %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă deschisă · %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открытый цикл · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorená slučka · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppen loop · %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Açık döngü · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкритий цикл · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp mở · %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "开环 · %1$@" + } + } + } + }, + "Open loop · not run yet" : { + "comment" : "Status pill on the Now screen: closed loop is off and Loop has never completed", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "حلقة مفتوحة · لم يعمل بعد" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevřená smyčka · zatím neproběhla" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbent Loop · ikke kørt endnu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Loop · noch nicht gelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Circuito abierto · aún no se ha ejecutado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avoin säätö · ei vielä ajettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Boucle ouverte · pas encore exécuté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Loop · טרם רץ" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nyitott hurok · még nem futott" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop aperto · non ancora eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "オープンループ · 未実行" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpen Loop · ikke kjørt ennå" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open loop · nog niet gedraaid" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pętla otwarta · jeszcze nie działała" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ciclo aberto · ainda não executou" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buclă deschisă · nu a rulat încă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открытый цикл · ещё не запускался" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorená slučka · ešte neprebehla" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppen loop · inte körd än" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Açık döngü · henüz çalışmadı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкритий цикл · ще не запускався" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vòng lặp mở · chưa chạy" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "开环 · 尚未运行" + } + } + } + }, + "Opens carb absorption" : { + "comment" : "VoiceOver hint for the COB tile on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يفتح امتصاص الكارب" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevře vstřebávání sacharidů" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbner kulhydratoptagelse" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffnet die KH-Aufnahme" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre la absorción de carbohidratos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaa hiilihydraattien imeytymisen" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvre l'absorption des glucides" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פותח ספיגת פחמימות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megnyitja a szénhidrát-felszívódást" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apre l'assorbimento dei carboidrati" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "糖質吸収を開きます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpner karbohydratabsorpsjon" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opent koolhydraatopname" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwiera wchłanianie węglowodanów" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre a absorção de carboidratos" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deschide absorbția carbohidraților" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открывает усвоение углеводов" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorí vstrebávanie sacharidov" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppnar kolhydratabsorption" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karb emilimini açar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкриває засвоєння вуглеводів" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mở hấp thu Carbs" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开碳水吸收" + } + } + } + }, + "Opens CGM settings" : { + "comment" : "VoiceOver hint for the CGM status pill and CGM notice on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يفتح إعدادات CGM" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevře nastavení CGM" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbner CGM-indstillinger" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffnet die CGM-Einstellungen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre los ajustes del CGM" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaa CGM-asetukset" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvre les paramètres du CGM" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פותח הגדרות CGM" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megnyitja a CGM beállításait" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apre le impostazioni CGM" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM設定を開きます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpner CGM-innstillinger" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opent CGM-instellingen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwiera ustawienia CGM" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre as configurações do CGM" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deschide setările CGM" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открывает настройки CGM" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorí nastavenia CGM" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppnar CGM-inställningar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM ayarlarını açar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкриває налаштування CGM" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mở cài đặt CGM" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开 CGM 设置" + } + } + } + }, + "Opens insulin delivery history" : { + "comment" : "VoiceOver hint for the IOB tile on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يفتح سجل توصيل الأنسولين" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevře historii podávání inzulínu" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbner historik for insulintilførsel" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffnet den Verlauf der Insulinabgabe" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre el historial de administración de insulina" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaa insuliinin annosteluhistorian" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvre l'historique d'administration de l'insuline" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פותח היסטוריית מתן אינסולין" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megnyitja az inzulinadagolási előzményeket" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apre la cronologia di erogazione insulina" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "インスリン注入履歴を開きます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpner historikk for insulinlevering" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opent geschiedenis van insulinetoediening" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwiera historię podaży insuliny" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre o histórico de entrega de insulina" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deschide istoricul administrării insulinei" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открывает историю подачи инсулина" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorí históriu podávania inzulínu" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppnar historik för insulindosering" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "İnsülin iletim geçmişini açar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкриває історію подачі інсуліну" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mở lịch sử tiêm insulin" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开胰岛素输注历史" + } + } + } + }, + "Opens Loop's prediction breakdown" : { + "comment" : "VoiceOver hint for the prediction card on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يفتح تفاصيل توقع Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevře rozpis predikce Loop" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbner opdelingen af Loops forudsigelse" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffnet die Aufschlüsselung der Loop-Vorhersage" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre el desglose de la predicción de Loop" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaa Loopin ennusteen erittelyn" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvre le détail de la prédiction de Loop" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פותח פירוט תחזית Loop" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megnyitja a Loop előrejelzésének részleteit" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apre il dettaglio della previsione di Loop" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopの予測の内訳を開きます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpner oppdelingen av Loops prognose" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opent de onderbouwing van de Loop-voorspelling" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwiera szczegóły prognozy Loop" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre o detalhamento da previsão do Loop" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deschide detalierea predicției Loop" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открывает разбор прогноза Loop" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorí rozpis predikcie Loop" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppnar detaljer om Loops prognos" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop tahmin dökümünü açar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкриває розбір прогнозу Loop" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mở chi tiết dự đoán của Loop" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开 Loop 预测明细" + } + } + } + }, + "Opens pump settings" : { + "comment" : "VoiceOver hint for the pump status pill and pump notice on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يفتح إعدادات المضخة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevře nastavení pumpy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbner pumpeindstillinger" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffnet die Pumpeneinstellungen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre los ajustes de la microinfusadora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaa pumpun asetukset" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvre les paramètres de la pompe" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פותח הגדרות משאבה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megnyitja a pumpa beállításait" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apre le impostazioni della pompa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプ設定を開きます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpner pumpeinnstillinger" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opent pompinstellingen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwiera ustawienia pompy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre as configurações da bomba" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deschide setările pompei" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открывает настройки помпы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorí nastavenia pumpy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppnar pumpinställningar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa ayarlarını açar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкриває налаштування помпи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mở cài đặt bơm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开胰岛素泵设置" + } + } + } + }, + "Opens the full day" : { + "comment" : "VoiceOver hint for the Today so far card on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يفتح اليوم كاملًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otevře celý den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åbner hele dagen" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öffnet den ganzen Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre el día completo" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avaa koko päivän" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvre la journée complète" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "פותח את היום המלא" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megnyitja a teljes napot" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apre il giorno completo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日全体を開きます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Åpner hele dagen" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opent de hele dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwiera cały dzień" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abre o dia completo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deschide ziua completă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открывает весь день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otvorí celý deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öppnar hela dagen" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tüm günü açar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Відкриває весь день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mở toàn bộ ngày" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "打开全天视图" + } + } + } + }, + "PDF report" : { + "comment" : "Trends export menu item: share a PDF report of the period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تقرير PDF" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zpráva PDF" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-rapport" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-Bericht" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Informe PDF" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-raportti" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rapport PDF" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "דוח PDF" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-jelentés" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Report PDF" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDFレポート" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-rapport" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-rapport" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Raport PDF" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Relatório PDF" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Raport PDF" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отчёт PDF" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Správa PDF" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF-rapport" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF raporu" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Звіт PDF" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Báo cáo PDF" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "PDF 报告" + } + } + } + }, + "per day, weekly average" : { + "comment" : "Trends Insulin per day card subtitle when each bar is a week's average daily total", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يوميًا، متوسط أسبوعي" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "za den, týdenní průměr" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "pr. dag, ugegennemsnit" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "pro Tag, Wochendurchschnitt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "por día, promedio semanal" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "päivässä, viikkokeskiarvo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "par jour, moyenne hebdomadaire" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ליום, ממוצע שבועי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "naponta, heti átlag" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "al giorno, media settimanale" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "1日あたり、週平均" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "per dag, ukesgjennomsnitt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "per dag, weekgemiddelde" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "dziennie, średnia tygodniowa" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "por dia, média semanal" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "pe zi, medie săptămânală" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "в день, среднее за неделю" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "za deň, týždenný priemer" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "per dag, veckomedel" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "günlük, haftalık ortalama" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "на день, середнє за тиждень" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "mỗi ngày, trung bình theo tuần" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "每日,按周平均" + } + } + } + }, + "Pod changed" : { + "comment" : "Pump event in the history: the pump or pod was replaced", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تم تغيير Pod" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod vyměněn" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod skiftet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod gewechselt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod cambiado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod vaihdettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod changé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "ה-Pod הוחלף" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod cserélve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod cambiato" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod交換" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod byttet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod vervangen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wymieniono poda" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod trocado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod schimbat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Под заменён" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod vymenený" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod bytt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pod değiştirildi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Под замінено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã thay Pod" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已更换 Pod" + } + } + } + }, + "Pre-meal" : { + "comment" : "Menu item under Presets on the Now screen that turns on the pre-meal target", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Před jídlem" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Før-måltid" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vor dem Essen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-comida" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennen ateriaa" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pré-repas" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-pasto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "食前" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-måltid" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voorafgaand aan maaltijd" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Przed posiłkiem" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pré-refeição" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Înainte de masă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "До еды" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pred jedlom" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Före måltid" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yemek öncesi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Перед їжою" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trước bữa ăn" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "餐前" + } + } + } + }, + "Pre-meal on" : { + "comment" : "Presets button title on the Now screen while the pre-meal target is on", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal مفعّل" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Před jídlem zapnuto" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Før-måltid til" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vor dem Essen an" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-comida activado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennen ateriaa päällä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pré-repas activé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal פעיל" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal bekapcsolva" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-pasto attivo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "食前 オン" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-måltid på" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voorafgaand aan maaltijd aan" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Przed posiłkiem wł." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pré-refeição ligado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Înainte de masă activ" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "До еды вкл." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pred jedlom zapnuté" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Före måltid på" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yemek öncesi açık" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Перед їжою увімк." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trước bữa ăn đang bật" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "餐前已开启" + } + } + } + }, + "Predicted" : { + "comment" : "Prediction chart callout label for Loop's predicted glucose at the touched time", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "متوقع" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikce" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forudsagt" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorhergesagt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predicción" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennustettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prédit" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "חזוי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előrejelzett" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prevista" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "予測" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forventet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voorspeld" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognoza" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prevista" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prezis" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predikcia" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Förutsagt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tahmin" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогноз" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dự đoán" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "预测" + } + } + } + }, + "Presets" : { + "comment" : "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الإعدادات المسبقة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Předvolby" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forudindstillinger" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voreinstellungen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajustes preestablecidos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esiasetukset" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Préréglages" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הגדרות מראש" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előbeállítások" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preimpostazioni" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "プリセット" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forhåndsinnstillinger" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Programma's" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ustawienia wstępne" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predefinições" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Presetări" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пресеты" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predvoľby" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Förinställningar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ön Ayarlar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пресети" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cài đặt sẵn" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "预设" + } + } + } + }, + "Previous day" : { + "comment" : "Accessibility label for the day page button that steps back a day", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اليوم السابق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Předchozí den" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forrige dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorheriger Tag" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Día anterior" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edellinen päivä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jour précédent" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "היום הקודם" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előző nap" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giorno precedente" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "前日" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forrige dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorige dag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poprzedni dzień" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dia anterior" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ziua anterioară" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Предыдущий день" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predchádzajúci deň" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Föregående dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Önceki gün" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Попередній день" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ngày trước" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "前一天" + } + } + } + }, + "Previous period" : { + "comment" : "VoiceOver label for the Trends button that moves back one period", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الفترة السابقة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Předchozí období" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forrige periode" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorheriger Zeitraum" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Período anterior" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edellinen jakso" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Période précédente" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "התקופה הקודמת" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előző időszak" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Periodo precedente" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "前の期間" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forrige periode" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorige periode" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poprzedni okres" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Período anterior" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Perioada anterioară" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Предыдущий период" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predchádzajúce obdobie" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Föregående period" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Önceki dönem" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Попередній період" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Khoảng thời gian trước" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "上一时段" + } + } + } + }, + "Primed" : { + "comment" : "Pump event in the history: the pump primed the tubing or cannula", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تمت التعبئة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Naplněno" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fyldt" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gefüllt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cebado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Täytetty" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Amorcé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "בוצע תיחול" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Feltöltve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Caricamento eseguito" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "プライミング" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fylt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gevuld" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Napełniono" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preenchido" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Amorsat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Заполнение выполнено" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Naplnené" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Primning klar" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dolum yapıldı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Заповнення виконано" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã mồi" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已充注" + } + } + } + }, + "Projected" : { + "comment" : "Chart legend: dashed lines show Loop's projection of insulin and carbs on board", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المتوقع" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Předpověď" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forventet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognose" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Proyectado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ennuste" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Projeté" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "צפי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Előrevetített" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Previsto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "予測" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beregnet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verwacht" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognozowane" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Projetado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Proiectat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогнозируемые" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predpoveď" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prognos" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Öngörülen" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прогнозовані" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dự kiến" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "预计" + } + } + } + }, + "Pump alarm" : { + "comment" : "Pump event in the history: an alarm whose pump gave no title", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إنذار المضخة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarm pumpy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpealarm" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpenalarm" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarma de la microinfusadora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpun hälytys" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarme de la pompe" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "התראת משאבה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpariasztás" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Allarme pompa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプアラーム" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpealarm" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompalarm" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarm pompy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarme da bomba" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarmă pompă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тревога помпы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alarm pumpy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumplarm" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa alarmı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тривога помпи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cảnh báo bơm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素泵警报" + } + } + } + }, + "Pump data too old" : { + "comment" : "Reason Loop could not run: the latest pump data was too old", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "بيانات المضخة قديمة جدًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data pumpy jsou příliš stará" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpedata for gamle" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpendaten zu alt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datos de la microinfusadora demasiado antiguos" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpun tiedot liian vanhoja" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Données de la pompe trop anciennes" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "נתוני המשאבה ישנים מדי" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Túl régi pumpaadatok" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dati pompa troppo vecchi" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプデータが古すぎます" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpedata for gamle" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompgegevens te oud" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dane pompy zbyt stare" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dados da bomba muito antigos" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date pompă prea vechi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Данные помпы устарели" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Údaje pumpy sú príliš staré" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpdata för gamla" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa verisi çok eski" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дані помпи застаріли" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dữ liệu bơm quá cũ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素泵数据过旧" + } + } + } + }, + "Pump manager error" : { + "comment" : "Reason Loop could not run: the pump reported an error", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "خطأ في مدير المضخة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba správce pumpy" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpefejl" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpenfehler" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error del gestor de la microinfusadora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpunhallinnan virhe" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erreur du gestionnaire de pompe" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "שגיאת מנהל המשאבה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpakezelő-hiba" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Errore del gestore pompa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプマネージャのエラー" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpefeil" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompfout" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Błąd menedżera pompy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erro do gerenciador da bomba" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eroare manager pompă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ошибка менеджера помпы" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chyba správcu pumpy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fel i pumphanteraren" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa yöneticisi hatası" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помилка менеджера помпи" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lỗi trình quản lý bơm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素泵管理器错误" + } + } + } + }, + "Pump suspended" : { + "comment" : "Reason Loop could not run: insulin delivery on the pump was suspended", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المضخة متوقفة مؤقتًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa pozastavena" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpe suspenderet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpe unterbrochen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Microinfusadora suspendida" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumppu pysäytetty" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompe suspendue" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "המשאבה מושהית" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa felfüggesztve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa sospesa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプ一時停止中" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpe stanset" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pomp onderbroken" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa wstrzymana" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bomba suspensa" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompă suspendată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помпа приостановлена" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa pozastavená" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pump pausad" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa askıya alındı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помпу призупинено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bơm đã tạm ngưng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "胰岛素泵已暂停" + } + } + } + }, + "Readings" : { + "comment" : "Chart legend on the Now screen: dots are CGM glucose readings", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القراءات" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hodnoty" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Målinger" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Messwerte" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lecturas" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lukemat" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mesures" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קריאות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mért értékek" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Letture" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "測定値" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Målinger" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Waarden" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Odczyty" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Leituras" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Citiri" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Показания" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hodnoty" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Värden" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Okumalar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Показники" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chỉ số" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "读数" + } + } + } + }, + "Recent readings unavailable: %1$@" : { + "comment" : "Error under the prediction chart on the Now screen. (1: system error description)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القراءات الأخيرة غير متاحة: %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nedávné hodnoty nejsou k dispozici: %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seneste målinger ikke tilgængelige: %1$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aktuelle Messwerte nicht verfügbar: %1$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lecturas recientes no disponibles: %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Viimeisimmät lukemat eivät saatavilla: %1$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mesures récentes indisponibles : %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "קריאות אחרונות אינן זמינות: %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A legutóbbi értékek nem érhetők el: %1$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Letture recenti non disponibili: %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "最近の測定値を取得できません:%1$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nylige målinger ikke tilgjengelige: %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recente waarden niet beschikbaar: %1$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostatnie odczyty niedostępne: %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Leituras recentes indisponíveis: %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Citiri recente indisponibile: %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Последние показания недоступны: %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nedávne hodnoty nie sú k dispozícii: %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senaste värden ej tillgängliga: %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Son okumalar kullanılamıyor: %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Останні показники недоступні: %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không có chỉ số gần đây: %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "最近读数不可用:%1$@" + } + } + } + }, + "Recommendation expired" : { + "comment" : "Reason Loop could not run: its dosing recommendation expired before it was used", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "انتهت صلاحية التوصية" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Doporučení vypršelo" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbefaling udløbet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Empfehlung abgelaufen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recomendación caducada" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suositus vanhentunut" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recommandation expirée" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "תוקף ההמלצה פג" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lejárt javaslat" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suggerimento scaduto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "推奨の有効期限切れ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anbefaling utløpt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advies verlopen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zalecenie wygasło" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recomendação expirada" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recomandare expirată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рекомендация устарела" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Odporúčanie vypršalo" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rekommendationen har gått ut" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Önerinin süresi doldu" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рекомендація застаріла" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Khuyến nghị đã hết hạn" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "建议已过期" + } + } + } + }, + "Reservoir changed" : { + "comment" : "Pump event in the history: the insulin reservoir was replaced", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تم تغيير الخزان" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zásobník vyměněn" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoir skiftet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoir gewechselt" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservorio cambiado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Säiliö vaihdettu" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Réservoir changé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "המאגר הוחלף" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tartály cserélve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Serbatoio cambiato" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "リザーバ交換" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoar byttet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoir vervangen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wymieniono zbiorniczek" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservatório trocado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezervor schimbat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Резервуар заменён" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zásobník vymenený" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoar bytt" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezervuar değiştirildi" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Резервуар замінено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã thay bình chứa" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已更换储药器" + } + } + } + }, + "Reservoir rewound" : { + "comment" : "Pump event in the history: the pump rewound its reservoir", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تم إرجاع الخزان" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zásobník převinut" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoir spolet tilbage" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoir zurückgespult" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservorio rebobinado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Säiliö kelattu taakse" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Réservoir rembobiné" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "המאגר הוחזר לאחור" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tartály visszatekerve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Serbatoio riavvolto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "リザーバ巻き戻し" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoar spolt tilbake" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoir teruggespoeld" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cofnięto tłok zbiorniczka" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservatório rebobinado" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezervor rebobinat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Резервуар перемотан" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zásobník pretočený" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reservoar tillbakaspolad" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezervuar geri sarıldı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Резервуар перемотано" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã tua lại bình chứa" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "储药器已回位" + } + } + } + }, + "Scheduled basal only" : { + "comment" : "Logbook day where only the scheduled basal ran, with nothing else logged", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "القاعدية المجدولة فقط" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jen plánovaný bazál" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kun planlagt basal" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nur geplante Basalrate" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Solo basal programada" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vain ohjelmoitu basaali" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal programmé uniquement" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal מתוזמן בלבד" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Csak ütemezett basal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Solo basale programmata" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "スケジュールのベーサルのみ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bare planlagt basal" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alleen gepland basaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tylko zaplanowana baza" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Somente basal programada" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Doar bazala programată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Только базал по расписанию" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Len plánovaný bazál" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Endast schemalagd basal" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yalnızca planlanan bazal" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лише базал за розкладом" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chỉ Basal theo lịch" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "仅预设基础率" + } + } + } + }, + "SD %1$@ · CV %2$@%%" : { + "comment" : "Trends Average tile detail: standard deviation and coefficient of variation of glucose. (1: standard deviation in the glucose unit, 2: coefficient of variation as a percentage number)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@ %%" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · VK %2$@ %%" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "DE %1$@ · CV %2$@%%" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@ %%" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ET %1$@ · CV %2$@ %%" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "DS %1$@ · CV %2$@%%" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@ %%" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "DP %1$@ · CV %2$@%%" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@ %%" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %%%2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "SD %1$@ · CV %2$@%%" + } + } + } + }, + "Sets up a CGM" : { + "comment" : "VoiceOver hint for the Add CGM status pill on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يُعدّ جهاز CGM" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nastaví CGM" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opsætter en CGM" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Richtet ein CGM ein" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configura un CGM" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ottaa CGM:n käyttöön" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configure un CGM" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מגדיר CGM" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM beállítása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configura un CGM" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGMを設定します" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Setter opp en CGM" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stelt een CGM in" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfiguruje CGM" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configura um CGM" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurează un CGM" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Настраивает CGM" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nastaví CGM" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lägger till en CGM" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM kurar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Налаштовує CGM" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thiết lập CGM" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "设置 CGM" + } + } + } + }, + "Sets up a pump" : { + "comment" : "VoiceOver hint for the Add pump status pill on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يُعدّ مضخة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nastaví pumpu" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opsætter en pumpe" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Richtet eine Pumpe ein" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configura una microinfusadora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ottaa pumpun käyttöön" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configure une pompe" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מגדיר משאבה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa beállítása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configura una pompa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "ポンプを設定します" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Setter opp en pumpe" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stelt een pomp in" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konfiguruje pompę" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configura uma bomba" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configurează o pompă" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Настраивает помпу" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nastaví pumpu" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lägger till en pump" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pompa kurar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Налаштовує помпу" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thiết lập bơm" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "设置胰岛素泵" + } + } + } + }, + "Shows when Loop last ran" : { + "comment" : "VoiceOver hint for the Loop status pill and the Loop notice on the Now screen", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "يعرض آخر مرة عمل فيها Loop" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ukáže, kdy Loop naposledy proběhl" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Viser, hvornår Loop sidst kørte" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zeigt, wann Loop zuletzt gelaufen ist" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Muestra cuándo se ejecutó Loop por última vez" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Näyttää, milloin Loop ajettiin viimeksi" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Indique la dernière exécution de Loop" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מציג מתי Loop רץ לאחרונה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Megmutatja, mikor futott utoljára a Loop" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostra l'ultima esecuzione di Loop" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loopの最終実行時刻を表示します" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Viser når Loop sist kjørte" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toont wanneer Loop voor het laatst draaide" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pokazuje, kiedy Loop ostatnio działał" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostra quando o Loop executou pela última vez" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Arată când a rulat Loop ultima dată" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Показывает, когда Loop запускался последний раз" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ukáže, kedy Loop naposledy prebehol" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Visar när Loop senast kördes" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loop'un son çalıştığı zamanı gösterir" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Показує, коли Loop запускався востаннє" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hiển thị lần chạy gần nhất của Loop" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "显示 Loop 上次运行时间" + } + } + } + }, + "Summary" : { + "comment" : "Trends card title: the summary statistics tiles", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الملخص" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Souhrn" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oversigt" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Übersicht" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Resumen" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yhteenveto" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Résumé" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "סיכום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Összegzés" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Riepilogo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "概要" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oversikt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Overzicht" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podsumowanie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Resumo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rezumat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сводка" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Súhrn" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sammanfattning" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Özet" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Підсумок" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tóm tắt" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "摘要" + } + } + } + }, + "Suspended" : { + "comment" : "Chart callout value: insulin delivery was suspended at the touched time Shown in the Basal tile on the Now screen when insulin delivery is suspended", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "متوقف مؤقتًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pozastaveno" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suspenderet" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unterbrochen" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suspendida" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pysäytetty" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suspendu" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מושהה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Felfüggesztve" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sospesa" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "一時停止中" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stanset" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Onderbroken" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wstrzymano" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suspensa" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suspendat" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Приостановлено" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pozastavené" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pausad" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Askıya alındı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Призупинено" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Đã tạm ngưng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "已暂停" + } + } + } + }, + "System" : { + "comment" : "Appearance option that follows the iPhone's light or dark setting", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "النظام" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systém" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "System" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "System" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistema" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Järjestelmä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Système" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מערכת" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rendszer" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistema" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "システム" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "System" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systeem" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systemowy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistema" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistem" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Как в системе" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systém" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "System" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistem" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Як у системі" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hệ thống" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "系统" + } + } + } + }, + "System follows your iPhone's light or dark setting." : { + "comment" : "Footer for the appearance choice", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "خيار النظام يتبع إعداد المظهر الفاتح أو الداكن في iPhone." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systém se řídí světlým nebo tmavým nastavením iPhonu." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "System følger din iPhones lyse eller mørke indstilling." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "„System“ folgt der hellen oder dunklen Einstellung Deines iPhones." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistema sigue el ajuste claro u oscuro de tu iPhone." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Järjestelmä seuraa iPhonen vaaleaa tai tummaa asetusta." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Système suit le réglage clair ou sombre de votre iPhone." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מערכת פועלת לפי הגדרת המראה הבהיר או הכהה של ה-iPhone." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "A Rendszer az iPhone világos vagy sötét beállítását követi." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistema segue l'impostazione chiara o scura del tuo iPhone." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "「システム」はiPhoneのライト/ダーク設定に従います。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "System følger den lyse eller mørke innstillingen på iPhonen din." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systeem volgt de lichte of donkere instelling van je iPhone." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systemowy wygląd jest zgodny z jasnym lub ciemnym ustawieniem iPhone’a." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistema segue o ajuste claro ou escuro do seu iPhone." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistem urmează setarea luminoasă sau întunecată a iPhone-ului." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "«Как в системе» следует светлому или тёмному оформлению iPhone." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Systém sa riadi svetlým alebo tmavým nastavením iPhonu." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "System följer iPhonens ljusa eller mörka inställning." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sistem, iPhone'unuzun açık veya koyu ayarını izler." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "«Як у системі» відповідає світлому або темному вигляду iPhone." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hệ thống theo cài đặt sáng hoặc tối của iPhone." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "“系统”跟随 iPhone 的浅色或深色设置。" + } + } + } + }, + "Target %1$@–%2$@" : { + "comment" : "Glucose target range on the Now screen hero card. (1: lower bound; 2: upper bound)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الهدف %1$@–%2$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cíl %1$@–%2$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mål %1$@–%2$@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ziel %1$@–%2$@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Objetivo %1$@–%2$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tavoite %1$@–%2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cible %1$@–%2$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "יעד %1$@–%2$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cél %1$@–%2$@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obiettivo %1$@–%2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "目標 %1$@–%2$@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mål %1$@–%2$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Doel %1$@–%2$@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cel %1$@–%2$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alvo %1$@–%2$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Țintă %1$@–%2$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Цель %1$@–%2$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cieľ %1$@–%2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mål %1$@–%2$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hedef %1$@–%2$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ціль %1$@–%2$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mục tiêu %1$@–%2$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "目标 %1$@–%2$@" + } + } + } + }, + "Temp basal" : { + "comment" : "Logbook row title: a temporary basal rate", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temp Basal" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dočasný bazál" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Midlertidig basal" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temporäre Basalrate" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal temporal" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temp Basal" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basal temp." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temp Basal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temp Basal" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basale temporanea" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "一時ベーサル" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Midlertidig basal" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tijdelijk basaal" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baza tymczasowa" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temp Basal" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bazală temporară" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Врем. базал" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dočasný bazál" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temporär basal" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geçici bazal oranı" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тимчасовий базал" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temp Basal" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "临时基础率" + } + } + } + }, + "The icon couldn't be changed: %@" : { + "comment" : "Error shown when iOS refuses an app icon change", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تعذّر تغيير الأيقونة: %@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikonu nelze změnit: %@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Symbolet kunne ikke ændres: %@" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Das Symbol konnte nicht geändert werden: %@" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No se pudo cambiar el icono: %@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kuvaketta ei voitu vaihtaa: %@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossible de changer l'icône : %@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "לא ניתן היה לשנות את הצלמית: %@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az ikont nem sikerült módosítani: %@" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Impossibile cambiare l'icona: %@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "アイコンを変更できませんでした:%@" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Symbolet kunne ikke endres: %@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Het symbool kan niet worden gewijzigd: %@" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nie udało się zmienić ikony: %@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Não foi possível alterar o ícone: %@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pictograma nu a putut fi schimbată: %@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не удалось сменить значок: %@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ikonu nie je možné zmeniť: %@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Symbolen kunde inte ändras: %@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Simge değiştirilemedi: %@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Не вдалося змінити іконку: %@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Không thể đổi biểu tượng: %@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "无法更改图标:%@" + } + } + } + }, + "The new interface adds Trends and Logbook tabs. Turn it off to go back to the classic status screen; Settings closes to switch." : { + "comment" : "Footer for the interface choice in settings", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "تضيف الواجهة الجديدة تبويبي الاتجاهات والسجل. أوقفها للعودة إلى شاشة الحالة الكلاسيكية؛ تُغلق الإعدادات للتبديل." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nové rozhraní přidává karty Trendy a Deník. Vypněte ho, chcete-li se vrátit ke klasické obrazovce stavu; Nastavení se pro přepnutí zavře." + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Den nye brugerflade tilføjer fanerne Tendenser og Logbog. Slå den fra for at vende tilbage til den klassiske statusskærm; Indstillinger lukkes for at skifte." + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Die neue Oberfläche fügt die Tabs Trends und Logbuch hinzu. Schalte sie aus, um zum klassischen Statusbildschirm zurückzukehren; die Einstellungen werden zum Wechseln geschlossen." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "La nueva interfaz añade las pestañas Tendencias y Registro. Desactívala para volver a la pantalla de estado clásica; Ajustes se cierra para cambiar." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Uusi käyttöliittymä lisää Trendit- ja Lokikirja-välilehdet. Poista se käytöstä palataksesi perinteiseen tilanäyttöön; Asetukset suljetaan vaihtoa varten." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "La nouvelle interface ajoute les onglets Tendances et Journal. Désactivez-la pour revenir à l'écran d'état classique ; les Paramètres se ferment pour basculer." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הממשק החדש מוסיף לשוניות מגמות ויומן. כבה אותו כדי לחזור למסך הסטטוס הקלאסי; ההגדרות ייסגרו לצורך המעבר." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Az új felület Trendek és Napló lapokkal bővül. Kapcsold ki, ha vissza szeretnél térni a klasszikus állapotképernyőhöz; a váltáshoz a Beállítások bezárul." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "La nuova interfaccia aggiunge le schede Tendenze e Diario. Disattivala per tornare alla classica schermata di stato; Impostazioni si chiude per cambiare." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "新しいインターフェイスではトレンドとログブックのタブが追加されます。オフにすると従来のステータス画面に戻ります。切り替えると設定が閉じます。" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Det nye grensesnittet legger til fanene Trender og Loggbok. Slå det av for å gå tilbake til den klassiske statusskjermen; Innstillinger lukkes for å bytte." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "De nieuwe interface voegt de tabbladen Trends en Logboek toe. Zet hem uit om terug te gaan naar het klassieke statusscherm; Instellingen sluit om te wisselen." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nowy interfejs dodaje karty Trendy i Dziennik. Wyłącz go, aby wrócić do klasycznego ekranu stanu; Ustawienia zamkną się, aby przełączyć." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "A nova interface adiciona as abas Tendências e Diário. Desligue-a para voltar à tela de status clássica; as Configurações fecham para trocar." + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Noua interfață adaugă filele Tendințe și Jurnal. Dezactivați-o pentru a reveni la ecranul de stare clasic; Setările se închid pentru comutare." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Новый интерфейс добавляет вкладки «Тренды» и «Журнал». Выключите его, чтобы вернуться к классическому экрану статуса; для переключения настройки закроются." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nové rozhranie pridáva karty Trendy a Denník. Vypnite ho, ak sa chcete vrátiť ku klasickej obrazovke stavu; Nastavenia sa pri prepnutí zatvoria." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Det nya gränssnittet lägger till flikarna Trender och Loggbok. Stäng av det för att gå tillbaka till den klassiska statusskärmen; Inställningar stängs vid bytet." + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yeni arayüz Eğilimler ve Kayıt Defteri sekmelerini ekler. Klasik durum ekranına dönmek için kapatın; geçiş için Ayarlar kapanır." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Новий інтерфейс додає вкладки «Тренди» і «Журнал». Вимкніть його, щоб повернутися до класичного екрана стану; для перемикання налаштування закриються." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Giao diện mới thêm các tab Xu hướng và Nhật ký. Tắt để quay lại màn hình trạng thái cổ điển; Cài đặt sẽ đóng để chuyển đổi." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "新界面增加了“趋势”和“日志”标签页。关闭后将返回经典状态屏幕;切换时设置会关闭。" + } + } + } + }, + "Time in range" : { + "comment" : "Trends card title: share of glucose readings in each range", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الوقت ضمن النطاق" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Čas v rozsahu" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tid i området" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zeit im Zielbereich" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tiempo en rango" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aika tavoitealueella" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Temps dans la cible" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "זמן בטווח" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tartományban töltött idő" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tempo nell'intervallo" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "範囲内時間" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tid i målområdet" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tijd binnen bereik" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Czas w zakresie" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tempo no alvo" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Timp în interval" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Время в диапазоне" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Čas v rozsahu" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tid inom målområdet" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aralıkta geçen süre" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Час у діапазоні" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thời gian trong khoảng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "目标范围内时间" + } + } + } + }, + "Today" : { + "comment" : "Day page title when showing today", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اليوم" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "I dag" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Heute" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoy" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tänään" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aujourd'hui" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "היום" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ma" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oggi" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "今日" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "I dag" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vandaag" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dziś" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoje" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Azi" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сегодня" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "I dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bugün" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сьогодні" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hôm nay" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "今天" + } + } + } + }, + "Today so far" : { + "comment" : "Title of the card on the Now screen showing today's insulin and carbs", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اليوم حتى الآن" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes zatím" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "I dag indtil nu" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Heute bisher" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoy hasta ahora" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tänään tähän mennessä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aujourd'hui jusqu'ici" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "היום עד כה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ma eddig" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ SUONI DELL'APP" + "value" : "Oggi finora" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "今日のこれまで" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ APP-LYDER" + "value" : "I dag så langt" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vandaag tot nu toe" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ DŹWIĘKI APLIKACJI" + "value" : "Dziś do tej pory" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoje até agora" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Azi până acum" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ ЗВУКИ ПРИЛОЖЕНИЯ" + "value" : "Сегодня на данный момент" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes zatiaľ" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hittills i dag" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bugün şu ana kadar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сьогодні наразі" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hôm nay đến giờ" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "今日至今" } } } }, - "%1$@ is operating with Closed Loop in the OFF position. Your pump and CGM will continue operating, but the app will not adjust dosing automatically." : { - "comment" : "Alert message for closed loop off informational modal. (1: app name)", + "Today · %1$@" : { + "comment" : "Logbook day header for today. (1: weekday and date, e.g. Sun 25 Oct)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "اليوم · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes · %1$@" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kører med Lukket Loop i positionen OFF. Din pumpe og CGM fortsætter med at fungere, men appen justerer ikke doseringen automatisk." + "value" : "I dag · %1$@" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ arbeitet mit geschlossenem Regelkreis in der AUS-Position. Deine Pumpe und CGM funktionieren weiter, aber die App passt die Dosierung nicht automatisch an." + "value" : "Heute · %1$@" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ está funcionando con Circuito Cerrado en la posición APAGADO. Su bomba y CGM seguirán funcionando, pero la aplicación no ajustará la dosis automáticamente." + "value" : "Hoy · %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tänään · %1$@" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ fonctionne avec la boucle fermée en position ARRÊT. Votre pompe et votre CGM continueront de fonctionner, mais l'application n'ajustera pas automatiquement le dosage." + "value" : "Aujourd'hui · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "היום · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ma · %1$@" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ è in funzione con Loop chiuso disattivato. La pompa e il CGM continueranno a funzionare, ma l'applicazione non regolerà automaticamente il dosaggio." + "value" : "Oggi · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "今日 · %1$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ opererer med Lukket Loop i AV-posisjon. Pumpen og CGM vil fortsette å fungere, men appen vil ikke justere doseringen automatisk." + "value" : "I dag · %1$@" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ werkt met Actieve loop UIT. Je pomp en CGM blijven werken, maar de app past de dosering niet automatisch aan." + "value" : "Vandaag · %1$@" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ działa z zamkniętą pętlą w pozycji OFF. Twoja pompa i CGM będą nadal działać, ale aplikacja nie będzie automatycznie dostosowywać insuliny." + "value" : "Dziś · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hoje · %1$@" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ operează cu bucla închisă în poziția OPRIT. Pompa și senzorul de glicemie vor continua să funcționeze, dar aplicația nu va ajusta automat dozarea." + "value" : "Azi · %1$@" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ работает с замкнутым циклом в положении ВЫКЛ. Ваша помпа и CGM будут продолжать работать, но приложение не будет регулировать дозировку автоматически." + "value" : "Сегодня · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dnes · %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "I dag · %1$@" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ , KAPALI konumda Kapalı Döngü ile çalışıyor. Pompanız ve CGM çalışmaya devam edecek, ancak uygulama dozajı otomatik olarak ayarlamayacaktır." + "value" : "Bugün · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сьогодні · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hôm nay · %1$@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 当前处于非闭环模式。胰岛素泵和连续血糖监测仪仍将正常运行,但应用程序不会自动调整胰岛素剂量。" + "value" : "今天 · %1$@" } } } }, - "%1$@ is unable to clear the alert from your device" : { - "comment" : "Message for alert shown when alert acknowledgement fails for a device, and the device does not provide a LocalizedError. (1: app name)", + "Touch and hold a chart to see exact values." : { + "comment" : "Hint under the day page charts explaining how to scrub them", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المس مخططًا مع الاستمرار لرؤية القيم الدقيقة." + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podržte prst na grafu a uvidíte přesné hodnoty." + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan ikke slette advarslen fra din enhed" + "value" : "Tryk og hold på et diagram for at se præcise værdier." } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kann die Benachrichtigung nicht von Deinem Gerät löschen" + "value" : "Halte ein Diagramm gedrückt, um genaue Werte zu sehen." } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ no puede borrar la alerta de su dispositivo" + "value" : "Mantén pulsado un gráfico para ver los valores exactos." + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pidä kaaviota painettuna nähdäksesi tarkat arvot." } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ ne parvient pas à supprimer l'alerte de votre dispositif." + "value" : "Touchez un graphique de manière prolongée pour voir les valeurs exactes." + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "גע והחזק תרשים כדי לראות ערכים מדויקים." + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Érints meg és tarts lenyomva egy diagramot a pontos értékekért." } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ non è in grado di cancellare l'avviso dal tuo dispositivo" + "value" : "Tieni premuto su un grafico per vedere i valori esatti." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "グラフを長押しすると正確な値が表示されます。" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan ikke fjerne varselet fra enheten din" + "value" : "Trykk og hold på et diagram for å se nøyaktige verdier." } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan de melding niet wissen van je apparaat" + "value" : "Houd een grafiek ingedrukt om exacte waarden te zien." } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ nie może usunąć alertu z Twojego urządzenia" + "value" : "Dotknij i przytrzymaj wykres, aby zobaczyć dokładne wartości." + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toque e segure um gráfico para ver os valores exatos." } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ nu poate șterge alerta de pe dispozitiv" + "value" : "Țineți apăsat pe un grafic pentru a vedea valorile exacte." } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ не удается удалить предупреждение с вашего устройства" + "value" : "Нажмите и удерживайте график, чтобы увидеть точные значения." + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podržte prst na grafe a uvidíte presné hodnoty." + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tryck och håll på ett diagram för att se exakta värden." } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ , uyarıyı cihazınızdan silemiyor" + "value" : "Tam değerleri görmek için bir grafiğe dokunup basılı tutun." + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Торкніться й утримуйте графік, щоб побачити точні значення." + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chạm và giữ biểu đồ để xem giá trị chính xác." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 无法清除您设备上的警报。" + "value" : "按住图表可查看精确数值。" } } } }, - "%1$@ is unable to communicate with your insulin pump. The app will continue trying to reach your pump, but insulin delivery information cannot be updated and no automation can continue.\nYou can wait several minutes to see if the issue resolves or tap the button below to learn more about other options." : { - "comment" : "Message for alert shown when delivery status is uncertain. (1: app name)", + "Trends" : { + "comment" : "Title of the Trends tab Title of the Trends tab in the redesigned interface", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "الاتجاهات" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan ikke kommunikere med insulinpumpen. Loop vil fortsætte med at forsøge at kommunikere med din pumpe, men insulinafgivelsesoplysninger kan ikke opdateres og ingen automatisering kan fortsætte.\nDu kan vente et par minutter for at se, om problemet bliver løst, eller tryk på knappen nedenfor for at få mere at vide om andre muligheder." + "value" : "Tendenser" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kann nicht mit Deiner Insulinpumpe kommunizieren. Die App versucht weiterhin, Deine Pumpe zu erreichen, aber die Informationen zur Insulinabgabe können nicht aktualisiert werden und die Automatisierung kann nicht fortgesetzt werden.\nDu kannst einige Minuten warten, um zu sehen, ob das Problem behoben ist, oder auf die Schaltfläche unten tippen, um mehr über andere Optionen zu erfahren." + "value" : "Trends" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ no puede comunicarse con tu bomba de insulina. La aplicación continuará intentando llegar a tu bomba, pero la información de entrega de insulina no se puede actualizar y ninguna automatización puede continuar.\nPuedes esperar varios minutos para ver si el problema resuelve o pulsa el botón de abajo para saber más sobre otras opciones." + "value" : "Tendencias" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ ei pysty kommunikoimaan insuliinipumpun kanssa. Sovellus yrittää edelleen yhdistää pumppuun, mutta insuliininannostelun tiedot eivät päivity, eikä automatiikka ole päällä.\nVoit odottaa muutaman minuutin nähdäksesi ratkeaako ongelma, tai voit napauttaa alla olevaa painiketta saadaksesi lisätietoja muista vaihtoehdoista." + "value" : "Trendit" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ ne parvient pas à communiquer avec votre pompe à insuline. L’application continuera d’essayer d’atteindre votre pompe, mais les informations sur l’administration d’insuline ne peuvent pas être mises à jour et aucune automatisation ne peut continuer.\nVous pouvez attendre quelques minutes pour voir si le problème est résolu ou appuyer sur le bouton ci-dessous pour en savoir plus sur les autres options." + "value" : "Tendances" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "מגמות" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendek" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ non riesce a comunicare con la pompa. L'app continuerà a provare a contattare la pompa, ma le informazioni sull'erogazione dell'insulina non possono essere aggiornate e l'automazione non può proseguire. \nPuoi attendere alcuni minuti per vedere se il problema si risolve oppure toccare il pulsante qui sotto per saperne di più sulle altre opzioni." + "value" : "Tendenze" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "トレンド" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan ikke kommunisere med insulinpumpen. Appen vil fortsette å prøve å nå pumpen din, men insulintilførselsinformasjon kan ikke oppdateres og ingen automatisering kan fortsette.\n Du kan vente flere minutter for å se om problemet løser seg eller trykke på knappen nedenfor for å lære mer om andre alternativer." + "value" : "Trender" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trends" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendências" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tendințe" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренды" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trendy" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trender" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eğilimler" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренди" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Xu hướng" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "趋势" + } + } + } + }, + "Turn off %1$@" : { + "comment" : "Menu item under Presets on the Now screen that turns off the active override preset. (1: preset name)", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إيقاف %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vypnout %1$@" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Slå %1$@ fra" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ ausschalten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desactivar %1$@" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poista %1$@ käytöstä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Désactiver %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "כבה %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ kikapcsolása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disattiva %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@をオフ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Slå av %1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ uitzetten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wyłącz %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desligar %1$@" + } + }, + "ro" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dezactivați %1$@" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Выключить %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vypnúť %1$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stäng av %1$@" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kapat: %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вимкнути %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tắt %1$@" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "关闭%1$@" + } + } + } + }, + "Turn off pre-meal" : { + "comment" : "Menu item under Presets on the Now screen that turns off the pre-meal target", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إيقاف Pre-Meal" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vypnout Před jídlem" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Slå før-måltid fra" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vor dem Essen ausschalten" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desactivar pre-comida" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Poista Ennen ateriaa käytöstä" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Désactiver pré-repas" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "כבה Pre-Meal" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pre-Meal kikapcsolása" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disattiva pre-pasto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "食前をオフ" + } + }, + "nb" : { + "stringUnit" : { + "state" : "translated", + "value" : "Slå av pre-måltid" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan niet communiceren met je insulinepomp. De app blijft proberen je pomp te bereiken, maar de insulinetoedieningsinformatie kan niet worden bijgewerkt en automatisering kan niet plaatsvinden.\nJe kunt enkele minuten wachten om te zien of het probleem is opgelost of tik op de onderstaande knop voor meer informatie over andere opties." + "value" : "Voorafgaand aan maaltijd uitzetten" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ nie może skomunikować się z Twoją pompą insulinową. Aplikacja będzie nadal próbowała połączyć się z pompą, ale nie można aktualizować informacji o podawaniu insuliny i nie można kontynuować automatyzacji.\n Możesz poczekać kilka minut, aby sprawdzić, czy problem został rozwiązany, lub nacisnąć poniższy przycisk, aby dowiedzieć się więcej o innych opcjach." + "value" : "Wyłącz Przed posiłkiem" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desligar pré-refeição" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ nu poate comunica cu pompa de insulină. Aplicația va continua să încerce să comunice cu pompa, dar informațiile despre administrarea insulinei nu pot fi actualizate și automatizarea nu poate continua.\nPuteți aștepta câteva minute pentru a vedea dacă problema se rezolvă sau apăsați butonul de mai jos pentru a afla mai multe despre alte opțiuni." + "value" : "Dezactivați Înainte de masă" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ не может связаться с вашей инсулиновой помпой. Приложение будет продолжать попытки связаться с вашей помпой, но информация о доставке инсулина не может быть обновлена, и автоматизация не может продолжаться.\nВы можете подождать несколько минут и посмотреть, разрешится ли проблема, или нажать кнопку ниже, чтобы узнать о других возможностях." + "value" : "Выключить «До еды»" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ nedokáže komunikovať s vašou inzulínovou pumpou. Aplikácia sa bude naďalej pokúšať kontaktovať vašu pumpu, ale informácie o podávaní inzulínu nemožno aktualizovať a nemôže pokračovať žiadna automatizácia.\nMôžete počkať niekoľko minút, aby ste zistili, či sa problém vyriešil, alebo klepnutím na tlačidlo nižšie sa dozviete viac o ďalších možnostiach." + "value" : "Vypnúť Pred jedlom" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ kan inte kommunicera med din insulinpump. Appen kommer att fortsätta att försöka nå din pump, men under tiden kan information om insulintillförsel inte uppdateras och automatisering inte fortsätta.\nDu kan vänta flera minuter för att se om problemet löser sig eller klicka på knappen nedan för att läsa mer om andra alternativ." + "value" : "Stäng av Före måltid" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ insülin pompanızla iletişim kuramıyor. Uygulama pompanıza ulaşmaya çalışmaya devam edecek, ancak insülin iletim bilgileri güncellenemeyecek ve hiçbir otomasyon devam edemeyecektir.\nSorunun çözülüp çözülmediğini görmek için birkaç dakika bekleyebilir veya diğer seçenekler hakkında daha fazla bilgi edinmek için aşağıdaki butona dokunabilirsiniz." + "value" : "Yemek öncesini kapat" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вимкнути «Перед їжою»" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tắt Trước bữa ăn" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 无法与您的胰岛素泵通信。应用将继续尝试连接胰岛素泵,但当前无法更新胰岛素输注信息,也无法继续自动化操作。\n\n您可以等待几分钟以观察问题是否自动恢复,或点击下方按钮了解其他可选操作。" + "value" : "关闭餐前" } } } }, - "%1$@ Time Settings Need Attention" : { - "comment" : "Time change alert title", + "U/h" : { + "comment" : "Abbreviation for insulin units per hour", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "وحدة لكل ساعة" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/hod" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Tidsindstillinger kræver opmærksomhed" + "value" : "E/t" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Zeiteinstellungen erfordern Aufmerksamkeit" + "value" : "IE/Std" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ La configuración de la hora necesita atención" + "value" : "U/h" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/h" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Paramètres d'heure requierent une attention" + "value" : "U/h" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ הגדרות השעה דורשות תשומת לב" + "value" : "U/hr" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/óra" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Le impostazioni dell'orario richiedono attenzione" + "value" : "U/ora" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "単位/時" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Tidsinnstillinger trenger oppmerksomhet" + "value" : "E/t" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Tijdinstellingen hebben aandacht nodig" + "value" : "E/uur" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ustawienia czasu wymagają uwagi" + "value" : "J/h" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/h" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Setările de timp necesită atenție" + "value" : "U/oră" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Настройки времени требуют внимания" + "value" : "Ед/ч" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "J/hod" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "IE/h" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Zaman Ayarlarına Dikkat Edilmesi Gerekiyor" + "value" : "Ü/Sa" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/год" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "U/giờ" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 时间设置需要注意" + "value" : "U/小时" } } } }, - "%1$@ U" : { - "comment" : "Reservoir entry (1: volume value)", + "unknown" : { + "comment" : "VoiceOver value when active insulin or carbs at the current time isn't known", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "غير معروف" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "neznámé" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E" + "value" : "ukendt" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ IE" + "value" : "unbekannt" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U" + "value" : "desconocido" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U" + "value" : "tuntematon" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U" + "value" : "inconnu" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "U %1$@" + "value" : "לא ידוע" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "ismeretlen" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U" + "value" : "sconosciuto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "不明" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E" + "value" : "ukjent" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E" + "value" : "onbekend" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ J" + "value" : "nieznane" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "desconhecido" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U" + "value" : "necunoscut" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ед." + "value" : "неизвестно" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%@ j" + "value" : "neznáme" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E" + "value" : "okänt" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ü" + "value" : "bilinmiyor" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "невідомо" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "không rõ" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U" + "value" : "未知" } } } }, - "%1$@ U left" : { - "comment" : "Low reservoir alert format string. (1: Number of units remaining)", - "extractionState" : "manual", + "Unknown error" : { + "comment" : "Reason Loop could not run: an unexpected error", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ وحدة متبقية" + "value" : "خطأ غير معروف" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E tilbage" + "value" : "Neznámá chyba" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ IE verbleibend" + "value" : "Ukendt fejl" } }, - "en" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U left" + "value" : "Unbekannter Fehler" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U restantes" + "value" : "Error desconocido" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U jäljellä" + "value" : "Tuntematon virhe" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U restantes" + "value" : "Erreur inconnue" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U נותרו" + "value" : "שגיאה לא ידועה" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ismeretlen hiba" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U rimaste" + "value" : "Errore sconosciuto" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "残 %1$@単位" + "value" : "不明なエラー" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E igjen" + "value" : "Ukjent feil" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E over" + "value" : "Onbekende fout" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ J pozostało" + "value" : "Nieznany błąd" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U restante" + "value" : "Erro desconhecido" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U rămase" + "value" : "Eroare necunoscută" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ед осталось" + "value" : "Неизвестная ошибка" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Zostáva %1$@ j" + "value" : "Neznáma chyba" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E kvar" + "value" : "Okänt fel" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ü kaldı" + "value" : "Bilinmeyen hata" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Невідома помилка" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U còn lại" + "value" : "Lỗi không xác định" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 单位 剩余" + "value" : "未知错误" } } } }, - "%1$@ U left: %2$@" : { - "comment" : "Low reservoir alert with time remaining format string. (1: Number of units remaining)(2: approximate time remaining)", - "extractionState" : "manual", + "Urgent low" : { + "comment" : "Pill under the glucose value on the Now screen when glucose is below 54 mg/dL (3.0 mmol/L)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ وحدة متبقية: %2$@" + "value" : "منخفض عاجل" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E tilbage: %2$@" + "value" : "Kriticky nízká" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ IE verbleibend: %2$@" + "value" : "Akut lav" } }, - "en" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U left: %2$@" + "value" : "Dringend niedrig" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U restantes: %2$@" + "value" : "Baja urgente" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U jäljellä: %2$@" + "value" : "Vaarallisen matala" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U restantes: %2$@" + "value" : "Basse urgente" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U נותרו: %2$@" + "value" : "נמוך דחוף" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sürgősen alacsony" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U rimaste: %2$@" + "value" : "Bassa urgente" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "残 %1$@単位: %2$@" + "value" : "緊急低値" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E gjenstår: %2$@" + "value" : "Akutt lav" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E over: %2$@" + "value" : "Urgent laag" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ J pozostało: %2$@" + "value" : "Krytycznie niska" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U restante: %2$@" + "value" : "Baixa urgente" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U rămase: %2$@" + "value" : "Urgent scăzută" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ед осталось: %2$@" + "value" : "Опасно низкая" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "Zostáva %1$@ j: %2$@" + "value" : "Kriticky nízka" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E kvar: %2$@" + "value" : "Akut lågt" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ü kalan: %2$@" + "value" : "Acil düşük" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Небезпечно низька" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U còn lại: %2$@" + "value" : "Thấp khẩn cấp" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 单位 剩余: %2$@" + "value" : "紧急低血糖" } } } }, - "%1$@ U/hour @ %2$@" : { - "comment" : "The format for recommended temp basal rate and time. (1: localized rate number)(2: localized time)", - "extractionState" : "manual", + "Very high" : { + "comment" : "Time in range band: glucose above 250 mg/dL (13.9 mmol/L) Time-in-range band name: glucose above 250 mg/dL (13.9 mmol/L)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ وحدة/ساعة @ %2$@" + "value" : "مرتفع جدًا" } }, - "da" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E/time @ %2$@" + "value" : "Velmi vysoká" } }, - "de" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ IE/h @ %2$@" + "value" : "Meget høj" } }, - "en" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/hour @ %2$@" + "value" : "Sehr hoch" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/hora @ %2$@" + "value" : "Muy alta" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/h klo %2$@" + "value" : "Erittäin korkea" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/heure @ %2$@" + "value" : "Très élevée" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ יח׳/שעה @ %2$@" + "value" : "גבוה מאוד" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nagyon magas" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/ora @ %2$@" + "value" : "Molto alta" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/時 @ %2$@" + "value" : "非常に高い" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E/timen @ %2$@" + "value" : "Svært høy" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E/uur @ %2$@" + "value" : "Zeer hoog" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ J/godzinę @ %2$@" + "value" : "Bardzo wysoka" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/hora @ %2$@" + "value" : "Muito alta" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/oră @ %2$@" + "value" : "Foarte ridicată" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ ед/час @ %2$@" + "value" : "Очень высокая" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ j/hod @ %2$@" + "value" : "Veľmi vysoká" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ E/h @ %2$@" + "value" : "Mycket högt" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ Ü/saat @ %2$@" + "value" : "Çok yüksek" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дуже висока" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ U/giờ @ %2$@" + "value" : "Rất cao" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 单位/小时 @ %2$@" + "value" : "非常高" } } } }, - "%1$@ v%2$@" : { - "comment" : "The format string for the app name and version number. (1: bundle name)(2: bundle version)", + "Very low" : { + "comment" : "Time in range band: glucose below 54 mg/dL (3.0 mmol/L) Time-in-range band name: glucose below 54 mg/dL (3.0 mmol/L)", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "منخفض جدًا" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Velmi nízká" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Meget lav" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Sehr niedrig" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Muy baja" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Erittäin matala" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Très basse" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "נמוך מאוד" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nagyon alacsony" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Molto bassa" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "非常に低い" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v %2$@" + "value" : "Svært lav" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Zeer laag" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Bardzo niska" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Muito baixa" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Foarte scăzută" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ версии %2$@" + "value" : "Очень низкая" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v %2$@" + "value" : "Veľmi nízka" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Mycket lågt" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Çok düşük" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дуже низька" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "Rất thấp" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ v%2$@" + "value" : "非常低" } } } }, - "%1$@ will stop working in %2$@. You will need to rebuild before that." : { - "comment" : "Format string for body for notification of upcoming expiration. (1: app name) (2: amount of time until expiration", + "vs plan" : { + "comment" : "Logbook basal adjustments row: the insulin amount is the difference from the scheduled basal", "localizations" : { - "da" : { + "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ holder op med at fungere i %2$@. Du bliver nødt til at rebuilde før det." + "value" : "مقارنة بالمجدول" } }, - "de" : { + "cs" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ funktioniert in %2$@ nicht mehr. Sie müssen vorher einen Neuaufbau durchführen." + "value" : "oproti plánu" } }, - "fr" : { + "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ cessera de fonctionner dans %2$@. Il vous faudra recompiler avant cette échéance." + "value" : "ift. plan" } }, - "it" : { + "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ smetterà di funzionare tra %2$@. Prima di allora, sarà necessario ricostruirlo." + "value" : "ggü. Plan" } }, - "nb" : { + "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ vil slutte å fungere i %2$@. Du må gjenoppbygge før det." + "value" : "vs. lo programado" } }, - "nl" : { + "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ stopt over %2$@ met werken. Bouw de app vóór die tijd opnieuw." + "value" : "vs. ohjelmoitu" } }, - "pl" : { + "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ przestanie działać w %2$@. Konieczna będzie wcześniejsza odbudowa." + "value" : "vs prévu" } }, - "ro" : { + "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ va înceta să funcționeze în %2$@. Va trebui să reconstruiți sistemul înainte de asta." + "value" : "לעומת התוכנית" } }, - "ru" : { + "hu" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ перестанет работать в %2$@. До этого времени необходимо пересобрать приложение заново." + "value" : "a tervhez képest" } }, - "zh-Hans" : { + "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@将在%2$@停止工作。您需要在此之前重建。" + "value" : "vs programmata" } - } - } - }, - "%1$@ will stop working in %2$@. You will need to update before that, with a new provisioning profile." : { - "comment" : "Format string for body for notification of upcoming provisioning profile expiration. (1: app name) (2: amount of time until expiration", - "localizations" : { - "da" : { + }, + "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ holder op med at fungere i %2$@. Du skal opdatere inden da med en ny provisioneringsprofil." + "value" : "予定比" } }, - "de" : { + "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ funktioniert nicht mehr in %2$@. Du musst vor Ablauf mit einem neuen Bereitstellungsprofil aktualisieren." + "value" : "mot plan" } }, - "es" : { + "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ dejará de funcionar en %2$@ . Deberá actualizar antes de eso, con un nuevo perfil de aprovisionamiento." + "value" : "t.o.v. gepland" } }, - "fr" : { + "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ cessera de fonctionner dans %2$@ . Vous devrez mettre à jour avant cela, avec un nouveau profil de provisioning." + "value" : "wzgl. planu" } }, - "it" : { + "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ smetterà di funzionare tra %2$@. Prima di allora, sarà necessario effettuare l'aggiornamento con un nuovo profilo di provisioning." + "value" : "vs. programado" } }, - "nb" : { + "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ slutter å fungere om %2$@ . Du må oppdatere før det, med en ny klargjøringsprofil." + "value" : "față de program" } }, - "nl" : { + "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ stopt met werken in %2$@. Je zult eerder moeten updaten, met een nieuw beschikbaargesteld profiel." + "value" : "к плану" } }, - "pl" : { + "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ przestanie działać za %2$@ . Wcześniej konieczna będzie aktualizacja przy użyciu nowego profilu udostępniania." + "value" : "oproti plánu" } }, - "ro" : { + "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ nu va mai funcționa în %2$@. Va trebui să actualizați înainte de aceasta, cu un nou profil de asigurare a accesului." + "value" : "mot schema" } }, - "ru" : { + "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ перестанет работать в %2$@. Вам нужно будет обновить его до этого, используя новую подпись." + "value" : "plana göre" } }, - "tr" : { + "uk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ %2$@ içinde çalışmayı durduracaktır. Bundan önce yeni bir provizyon profili ile güncelleme yapmanız gerekecektir." + "value" : "до плану" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "so với lịch" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ 在 %2$@中将无法正常工作。您需要在该版本发布之前,使用新的配置文件进行更新。" + "value" : "较预设" } } } }, - "%1$@: %2$@" : { - "comment" : "Formats (1: carb value) and (2: food type)", + "Workout" : { + "comment" : "Name shown on the Now screen's Presets button when the legacy workout override is active", "localizations" : { "ar" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "التمارين" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cvičení" } }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Motion" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Training" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Ejercicio" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Liikunta" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Exercice" } }, "he" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Workout" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Workout" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Allenamento" } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "運動" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ : %2$@" + "value" : "Trening" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ : %2$@" + "value" : "Training (sport)" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Wysiłek fizyczny" } }, "pt-BR" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Exercício" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Activitate sportivă" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Физическая нагрузка" } }, "sk" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ : %2$@" + "value" : "Tréning" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Träning" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Egzersiz" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренування" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "Workout" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@" + "value" : "锻炼/运动模式" } } } }, - "%1$@: %2$@ %3$@" : { - "comment" : "Description of a basal temp basal dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit)\nDescription of a bolus dose entry (1: title for dose type, 2: value (? if no value) in bold, 3: unit)", + "Yesterday · %1$@" : { + "comment" : "Logbook day header for yesterday. (1: weekday and date, e.g. Sat 24 Oct)", "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "أمس · %1$@" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Včera · %1$@" + } + }, "da" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "I går · %1$@" } }, "de" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Gestern · %1$@" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Ayer · %1$@" } }, "fi" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Eilen · %1$@" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Hier · %1$@" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "אתמול · %1$@" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tegnap · %1$@" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Ieri · %1$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "昨日 · %1$@" } }, "nb" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@ : %2$@ %3$@" + "value" : "I går · %1$@" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Gisteren · %1$@" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Wczoraj · %1$@" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ontem · %1$@" } }, "ro" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Ieri · %1$@" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Вчера · %1$@" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Včera · %1$@" } }, "sv" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "I går · %1$@" } }, "tr" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "Dün · %1$@" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Учора · %1$@" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hôm qua · %1$@" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "%1$@: %2$@ %3$@" + "value" : "昨天 · %1$@" } } } @@ -5396,6 +37055,24 @@ "state" : "translated", "value" : "添加CGM" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Přidat CGM" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "CGM hozzáadása" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додати CGM" + } } } }, @@ -9533,6 +41210,24 @@ "state" : "translated", "value" : "大剂量" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bolus" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bólus" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Болюс" + } } } }, @@ -14791,6 +46486,108 @@ "state" : "translated", "value" : "自定义预设" } + }, + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "إعداد مسبق مخصص" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vlastní předvolba" + } + }, + "da" : { + "stringUnit" : { + "state" : "translated", + "value" : "Brugerdefineret forudindstilling" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajuste preestablecido personalizado" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mukautettu esiasetus" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "הגדרה מראש מותאמת" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Egyéni előbeállítás" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Programmazione" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "カスタムプリセット" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cel Tymczasowy" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Predefinição personalizada" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пользовательский пресет" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vlastná predvoľba" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anpassad förinställning" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Özel ön ayar" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Власний пресет" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cài đặt sẵn tùy chỉnh" + } } } }, @@ -15248,8 +47045,33 @@ "state" : "translated", "value" : "删除" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Smazat" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Törlés" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "削除" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Видалити" + } } - } + }, + "comment" : "Swipe action to delete a Logbook entry" }, "Delete “%@”?" : { "localizations" : { @@ -20377,6 +52199,24 @@ "state" : "translated", "value" : "克" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "g" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "г" + } } } }, @@ -20585,6 +52425,18 @@ "state" : "translated", "value" : "血糖" } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Glükóz" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Глюкоза" + } } } }, @@ -22264,6 +54116,30 @@ "state" : "translated", "value" : "胰岛素" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulin" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inzulín" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Інсулін" + } } } }, @@ -29976,6 +61852,18 @@ "state" : "translated", "value" : "OK" } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } } } }, @@ -31662,6 +63550,30 @@ "state" : "translated", "value" : "胰岛素泵" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pumpa" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помпа" + } } } }, @@ -34297,6 +66209,18 @@ "state" : "translated", "value" : "重试" } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Újra" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Спробувати ще раз" + } } } }, @@ -34639,6 +66563,66 @@ "state" : "translated", "value" : "预设" } + }, + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "المجدول" + } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plánovaný" + } + }, + "fi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ohjelmoitu" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ütemezett" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "スケジュール" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Programada" + } + }, + "sk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Plánovaný" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schemalagd" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "За розкладом" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Theo lịch" + } } } }, @@ -35047,6 +67031,24 @@ "state" : "translated", "value" : "设置" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nastavení" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beállítások" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Налаштування" + } } } }, @@ -39077,6 +71079,24 @@ "state" : "translated", "value" : "U" } + }, + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "U" + } + }, + "hu" : { + "stringUnit" : { + "state" : "translated", + "value" : "U" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "U" + } } } }, diff --git a/Loop/Managers/DeeplinkManager.swift b/Loop/Managers/DeeplinkManager.swift index 86b17f625b..145d868d98 100644 --- a/Loop/Managers/DeeplinkManager.swift +++ b/Loop/Managers/DeeplinkManager.swift @@ -25,27 +25,28 @@ enum Deeplink: String, CaseIterable { class DeeplinkManager { - private weak var rootViewController: UIViewController? + /// The window's root changes when the interface is switched, so it is looked up on each link. + private let rootViewController: () -> UIViewController? - init(rootViewController: UIViewController?) { + init(rootViewController: @escaping () -> UIViewController?) { self.rootViewController = rootViewController } func handle(_ url: URL) -> Bool { - guard let rootViewController = rootViewController as? RootNavigationController, let deeplink = Deeplink(url: url) else { + guard let deeplink = Deeplink(url: url) else { return false } - rootViewController.navigate(to: deeplink) - return true + return handle(deeplink) } func handle(_ deeplink: Deeplink) -> Bool { - guard let rootViewController = rootViewController as? RootNavigationController else { + guard let root = rootViewController(), let rootNavigationController = root.loopRootNavigationController else { return false } - rootViewController.navigate(to: deeplink) + (root as? MainTabBarController)?.showNow() + rootNavigationController.navigate(to: deeplink) return true } } diff --git a/Loop/Managers/LoopAppManager.swift b/Loop/Managers/LoopAppManager.swift index efe8d2ad67..f9f2372657 100644 --- a/Loop/Managers/LoopAppManager.swift +++ b/Loop/Managers/LoopAppManager.swift @@ -171,6 +171,7 @@ class LoopAppManager: NSObject { precondition(state == .launchManagers) windowProvider?.window?.tintColor = .loopAccent + windowProvider?.window?.overrideUserInterfaceStyle = LoopAppearancePreference.current.interfaceStyle OrientationLock.deviceOrientationController = self UNUserNotificationCenter.current().delegate = self @@ -243,7 +244,7 @@ class LoopAppManager: NSObject { windowProvider: windowProvider, userDefaults: UserDefaults.appGroup!) - deeplinkManager = DeeplinkManager(rootViewController: rootViewController) + deeplinkManager = DeeplinkManager(rootViewController: { [weak self] in self?.rootViewController }) for support in supportManager.availableSupports { if let analyticsService = support as? AnalyticsService { @@ -294,6 +295,26 @@ class LoopAppManager: NSObject { .assign(to: \.automaticDosingStatus.automaticDosingEnabled, on: self) .store(in: &cancellables) + // Loop's stored runs don't say whether closed loop was on, so the Trends screen keeps its own record. + // dropFirst skips the placeholder AutomaticDosingStatus starts with; the debounce swallows the brief + // "not allowed yet" while devices come up at launch, so it isn't recorded as open loop. + automaticDosingStatus.$automaticDosingEnabled + .dropFirst() + .debounce(for: .seconds(15), scheduler: RunLoop.main) + .removeDuplicates() + .sink { LoopModeHistory.shared.record(closedLoop: $0) } + .store(in: &cancellables) + + NotificationCenter.default.publisher(for: LoopAppearancePreference.didChange) + .receive(on: RunLoop.main) + .sink { [weak self] _ in self?.windowProvider?.window?.overrideUserInterfaceStyle = LoopAppearancePreference.current.interfaceStyle } + .store(in: &cancellables) + + NotificationCenter.default.publisher(for: LoopInterfacePreference.didChange) + .receive(on: RunLoop.main) + .sink { [weak self] _ in self?.relaunchHomeScreenForInterfaceChange() } + .store(in: &cancellables) + state = state.next } @@ -309,10 +330,8 @@ class LoopAppManager: NSObject { } } - private func launchHomeScreen() { - dispatchPrecondition(condition: .onQueue(.main)) - precondition(state == .launchHomeScreen) - + /// Builds the status screen and makes it (or the redesign's tabs around it) the window's root. + private func installHomeScreen() { let storyboard = UIStoryboard(name: "Main", bundle: Bundle(for: Self.self)) let statusTableViewController = storyboard.instantiateViewController(withIdentifier: "MainStatusViewController") as! StatusTableViewController statusTableViewController.alertPermissionsChecker = alertPermissionsChecker @@ -324,13 +343,37 @@ class LoopAppManager: NSObject { statusTableViewController.testingScenariosManager = testingScenariosManager bluetoothStateManager.addBluetoothObserver(statusTableViewController) - var rootNavigationController = rootViewController as? RootNavigationController - if rootNavigationController == nil { - rootNavigationController = RootNavigationController() - rootViewController = rootNavigationController + LoopInterfacePreference.syncToExtensions() + if LoopInterfacePreference.useRedesign { + let rootNavigationController = RootNavigationController() + rootNavigationController.setViewControllers([statusTableViewController], animated: false) + rootViewController = MainTabBarController(rootNavigationController: rootNavigationController, deviceManager: deviceDataManager) + } else { + var rootNavigationController = rootViewController as? RootNavigationController + if rootNavigationController == nil { + rootNavigationController = RootNavigationController() + rootViewController = rootNavigationController + } + + rootNavigationController?.setViewControllers([statusTableViewController], animated: true) + } + } + + /// Swaps between the classic and redesigned interface once Loop is running. + private func relaunchHomeScreenForInterfaceChange() { + guard state == .launchComplete else { return } + if let presented = rootViewController?.presentedViewController { + presented.dismiss(animated: true) { [weak self] in self?.installHomeScreen() } + } else { + installHomeScreen() } + } + + private func launchHomeScreen() { + dispatchPrecondition(condition: .onQueue(.main)) + precondition(state == .launchHomeScreen) - rootNavigationController?.setViewControllers([statusTableViewController], animated: true) + installHomeScreen() deviceDataManager.refreshDeviceData() diff --git a/Loop/Redesign/AppearanceSettings.swift b/Loop/Redesign/AppearanceSettings.swift new file mode 100644 index 0000000000..437af384d5 --- /dev/null +++ b/Loop/Redesign/AppearanceSettings.swift @@ -0,0 +1,203 @@ +// +// AppearanceSettings.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import UIKit + +/// Light, dark or the system's choice, applied to Loop's whole window. +enum LoopAppearancePreference: String, CaseIterable, Identifiable { + case system + case light + case dark + + private static let key = "com.loopkit.Loop.redesign.appearance" + + static let didChange = Notification.Name("LoopAppearancePreferenceDidChange") + + static var current: LoopAppearancePreference { + get { UserDefaults.standard.string(forKey: key).flatMap(LoopAppearancePreference.init(rawValue:)) ?? .system } + set { + guard newValue != current else { return } + UserDefaults.standard.set(newValue.rawValue, forKey: key) + NotificationCenter.default.post(name: didChange, object: nil) + } + } + + var id: String { rawValue } + + var title: String { + switch self { + case .system: return NSLocalizedString("System", comment: "Appearance option that follows the iPhone's light or dark setting") + case .light: return NSLocalizedString("Day", comment: "Appearance option that always uses light mode") + case .dark: return NSLocalizedString("Night", comment: "Appearance option that always uses dark mode") + } + } + + var interfaceStyle: UIUserInterfaceStyle { + switch self { + case .system: return .unspecified + case .light: return .light + case .dark: return .dark + } + } +} + +/// The home screen icons Loop ships. Classic is the primary icon; the others are alternate icon sets in DerivedAssetsBase. +enum LoopAppIcon: String, CaseIterable, Identifiable { + case classic + case dayAndNight + case day + case night + + var id: String { rawValue } + + /// The asset catalog name passed to `setAlternateIconName`; nil is the primary icon. + var alternateIconName: String? { + switch self { + case .classic: return nil + case .dayAndNight: return "AppIconDayNight" + case .day: return "AppIconDay" + case .night: return "AppIconNight" + } + } + + var title: String { + switch self { + case .classic: return NSLocalizedString("Classic", comment: "Name of Loop's original app icon") + case .dayAndNight: return NSLocalizedString("Day and Night", comment: "Name of the app icon that follows the home screen's light or dark appearance") + case .day: return NSLocalizedString("Day", comment: "Name of the light app icon") + case .night: return NSLocalizedString("Night", comment: "Name of the dark app icon") + } + } + + var detail: String? { + switch self { + case .dayAndNight: return NSLocalizedString("Changes with the home screen's light or dark appearance", comment: "Description of the app icon that follows the home screen appearance") + default: return nil + } + } + + static var current: LoopAppIcon { + let name = UIApplication.shared.alternateIconName + return allCases.first { $0.alternateIconName == name } ?? .classic + } + + /// The preview shown in Settings. iOS doesn't expose alternate icons as images, so they have their own + /// preview image sets; Classic is read from the primary icon files, which a workspace may override. + var preview: UIImage? { + switch self { + case .classic: break + case .dayAndNight: return UIImage(named: "AppIconPreviewDayNight") + case .day: return UIImage(named: "AppIconPreviewDay") + case .night: return UIImage(named: "AppIconPreviewNight") + } + let icons = Bundle.main.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any] + let entry = icons?["CFBundlePrimaryIcon"] as? [String: Any] + if let files = entry?["CFBundleIconFiles"] as? [String] { + for file in files.reversed() { + if let image = UIImage(named: file) { return image } + } + } + return (entry?["CFBundleIconName"] as? String).flatMap { UIImage(named: $0) } + } +} + +/// Settings → Appearance: day or night for the app, and which icon the home screen shows. +struct AppearanceSettingsView: View { + @State private var appearance = LoopAppearancePreference.current + @State private var icon = LoopAppIcon.current + @State private var iconError: String? + + var body: some View { + List { + Section(footer: Text(NSLocalizedString("System follows your iPhone's light or dark setting.", comment: "Footer for the appearance choice"))) { + Picker(NSLocalizedString("Appearance", comment: "Title of the light or dark appearance choice"), selection: $appearance) { + ForEach(LoopAppearancePreference.allCases) { option in + Text(option.title).tag(option) + } + } + .pickerStyle(.segmented) + .onChange(of: appearance) { LoopAppearancePreference.current = $0 } + } + + Section(header: Text(NSLocalizedString("App Icon", comment: "Header for the app icon choice")), footer: iconFooter) { + ForEach(LoopAppIcon.allCases) { option in + Button { + choose(option) + } label: { + AppIconRow(icon: option, isSelected: option == icon) + } + .buttonStyle(.plain) + } + } + } + .listStyle(.insetGrouped) + .navigationTitle(NSLocalizedString("Appearance", comment: "Title of the appearance settings screen")) + } + + @ViewBuilder + private var iconFooter: some View { + if let iconError { + Text(iconError).foregroundStyle(LoopDesign.Palette.criticalInk) + } + } + + private func choose(_ option: LoopAppIcon) { + guard option != icon, UIApplication.shared.supportsAlternateIcons else { return } + UIApplication.shared.setAlternateIconName(option.alternateIconName) { error in + DispatchQueue.main.async { + // iOS can report an error from the "icon changed" alert even though the icon did change, + // so the icon iOS now reports decides. + if let error, UIApplication.shared.alternateIconName != option.alternateIconName { + iconError = String(format: NSLocalizedString("The icon couldn't be changed: %@", comment: "Error shown when iOS refuses an app icon change"), error.localizedDescription) + } else { + iconError = nil + icon = option + } + } + } + } +} + +private struct AppIconRow: View { + let icon: LoopAppIcon + let isSelected: Bool + + var body: some View { + HStack(spacing: LoopDesign.Space.s3) { + Group { + if let image = icon.preview { + Image(uiImage: image).resizable() + } else { + LoopDesign.Palette.surfaceSunken + } + } + .frame(width: 52, height: 52) + .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous)) + .overlay(RoundedRectangle(cornerRadius: 12, style: .continuous).strokeBorder(LoopDesign.Palette.separator, lineWidth: 0.5)) + .accessibilityHidden(true) + VStack(alignment: .leading, spacing: 2) { + Text(icon.title) + .foregroundStyle(LoopDesign.Palette.ink) + if let detail = icon.detail { + Text(detail) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(LoopDesign.Palette.inkMuted) + } + } + Spacer(minLength: 0) + if isSelected { + Image(systemName: "checkmark") + .font(.body.weight(.semibold)) + .foregroundStyle(LoopDesign.Palette.accent) + } + } + .contentShape(Rectangle()) + .accessibilityElement(children: .combine) + .accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton) + } +} diff --git a/Loop/Redesign/DayCharts.swift b/Loop/Redesign/DayCharts.swift new file mode 100644 index 0000000000..5fc8222563 --- /dev/null +++ b/Loop/Redesign/DayCharts.swift @@ -0,0 +1,639 @@ +// +// DayCharts.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import Charts +import UIKit + +private typealias P = LoopDesign.Palette + +// MARK: - Shared axis helpers + +enum DayAxis { + /// Midnight, 6 AM, noon and 6 PM inside `window`, by the clock, so a day when the clocks change still marks 6 AM. + static func quarterDayMarks(in window: DateInterval, calendar: Calendar = .current) -> [Date] { + var marks: [Date] = [] + var day = calendar.startOfDay(for: window.start) + while day <= window.end { + for hour in [0, 6, 12, 18] { + if let mark = calendar.date(bySettingHour: hour, minute: 0, second: 0, of: day), window.contains(mark) { + marks.append(mark) + } + } + guard let next = calendar.date(byAdding: .day, value: 1, to: day) else { break } + day = next + } + return marks + } + + static func hourLabel(_ date: Date) -> String { + date.formatted(.dateTime.hour()) + } + + /// Gaps of more than 30 minutes between readings, so a chart can say where data is missing. + static func gaps(in points: [GlucosePoint], window: DateInterval, until end: Date) -> [DateInterval] { + let limit: TimeInterval = 30 * 60 + var gaps: [DateInterval] = [] + var previous = window.start + for point in points.sorted(by: { $0.date < $1.date }) where window.contains(point.date) { + if point.date.timeIntervalSince(previous) > limit { + gaps.append(DateInterval(start: previous, end: point.date)) + } + previous = point.date + } + let last = min(end, window.end) + if last.timeIntervalSince(previous) > limit { + gaps.append(DateInterval(start: previous, end: last)) + } + return gaps + } + + static func gapMessage(_ gaps: [DateInterval], window: DateInterval, until end: Date) -> String? { + guard let longest = gaps.max(by: { $0.duration < $1.duration }) else { return nil } + // A gap over the whole period would read "0:00 – 0:00". + if gaps.count == 1, longest.start == window.start, longest.end == min(end, window.end) { + return window.contains(end) + ? NSLocalizedString("No CGM data yet today", comment: "Chart note: there are no glucose readings so far today") + : NSLocalizedString("No CGM data on this day", comment: "Chart note: there are no glucose readings for the whole day") + } + let start = LoopFormat.time(longest.start) + let end = LoopFormat.time(longest.end) + if gaps.count > 1 { + let others = String.localizedStringWithFormat(NSLocalizedString("%lld shorter gaps", comment: "Chart note: how many other, shorter gaps in glucose readings there were; follows the longest gap. (1: number of gaps)"), gaps.count - 1) + return String(format: NSLocalizedString("No CGM data %1$@ – %2$@ and %3$@", comment: "Chart note: the longest gap in glucose readings, plus the shorter ones. (1: start time; 2: end time; 3: number of shorter gaps, e.g. 2 shorter gaps)"), start, end, others) + } + return String(format: NSLocalizedString("No CGM data %1$@ – %2$@", comment: "Chart note: a gap in glucose readings. (1: start time; 2: end time)"), start, end) + } +} + +// MARK: - InsulinTimeline + +/// Carbs, glucose and insulin for one day on one shared time axis. +/// +/// The lanes are drawn in a single chart with stacked y ranges so they can't drift apart: insulin 0–30, +/// glucose 36–92 (the fixed 2–20 mmol/L scale), carb markers at 97. +struct InsulinTimelineView: View { + let history: DayHistory + let unit: GlucoseUnitStyle + let targetBands: [TargetBand] + var now: Date = Date() + var height: CGFloat = 260 + + @State private var selection: Date? + + private static let insulinTop = 30.0 + private static let basalTop = 12.0 + private static let glucoseRange = 36.0...92.0 + private static let carbLane = 97.0 + + private var window: DateInterval { history.window } + + private func y(glucose mgdl: Double) -> Double { + let domain = unit.dayDomain + let value = min(max(unit.value(mgdl), domain.lowerBound), domain.upperBound) + let fraction = (value - domain.lowerBound) / (domain.upperBound - domain.lowerBound) + return Self.glucoseRange.lowerBound + fraction * (Self.glucoseRange.upperBound - Self.glucoseRange.lowerBound) + } + + private var maxBasal: Double { + max(0.5, (history.basal.map(\.rate) + history.scheduledBasal.map(\.rate)).max() ?? 0) + } + + private var maxBolus: Double { + max(1, history.boluses.map(\.units).max() ?? 0) + } + + private func y(basal rate: Double) -> Double { rate / maxBasal * Self.basalTop } + private func y(bolus units: Double) -> Double { max(1.5, units / maxBolus * (Self.insulinTop - 4)) } + + private var gaps: [DateInterval] { DayAxis.gaps(in: history.glucose, window: window, until: now) } + + /// Labels closer than this to the previous label are dropped so they don't overprint; the marks still draw. + private var labelSpacing: TimeInterval { window.duration / 7 } + + private func spacedIDs(_ items: [T], date: (T) -> Date, id: (T) -> String) -> Set { + var kept = Set() + var last: Date? + for item in items.sorted(by: { date($0) < date($1) }) { + if let last, date(item).timeIntervalSince(last) < labelSpacing { continue } + kept.insert(id(item)) + last = date(item) + } + return kept + } + + private var labelledCarbs: Set { spacedIDs(history.carbs, date: \.date, id: \.id) } + private var labelledBoluses: Set { spacedIDs(history.boluses.filter { !$0.automatic }, date: \.date, id: \.id) } + + var body: some View { + VStack(alignment: .leading, spacing: LoopDesign.Space.s2) { + chart + .frame(height: height) + if let message = DayAxis.gapMessage(gaps, window: window, until: now), history.source == .loop || !history.glucose.isEmpty { + Text(message) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(LoopDesign.Palette.inkMuted) + } + } + } + + private var chart: some View { + Chart { + // Quarter-day rules + ForEach(DayAxis.quarterDayMarks(in: window), id: \.self) { mark in + RuleMark(x: .value("Time", mark)) + .foregroundStyle(P.grid) + .lineStyle(StrokeStyle(lineWidth: 1)) + } + + // Glucose lane + ForEach(Array(targetBands.enumerated()), id: \.offset) { _, band in + RectangleMark(xStart: .value("Start", band.start), xEnd: .value("End", band.end), + yStart: .value("Low", y(glucose: band.range.lowerBound)), yEnd: .value("High", y(glucose: band.range.upperBound))) + .foregroundStyle(P.targetBand) + } + ForEach(Array(history.glucose.enumerated()), id: \.offset) { _, point in + PointMark(x: .value("Time", point.date), y: .value("Glucose", y(glucose: point.mgdl))) + .symbolSize(10) + .foregroundStyle(P.glucose) + } + + // Carb markers + let carbLabels = labelledCarbs + ForEach(history.carbs) { carb in + PointMark(x: .value("Time", carb.date), y: .value("Carbs", Self.carbLane)) + .symbolSize(60) + .foregroundStyle(P.carbs) + .annotation(position: .trailing, spacing: 2) { + if carbLabels.contains(carb.id) { + Text(LoopFormat.grams(carb.grams)) + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.carbsInk) + } + } + } + + // Delivered basal, edged, then the schedule dashed over it + // Draw each recorded segment independently; a gap must not become an interpolated delivery area. + ForEach(Array(history.basal.enumerated()), id: \.offset) { _, segment in + RectangleMark(xStart: .value("Start", segment.start), xEnd: .value("End", segment.end), + yStart: .value("Base", 0), yEnd: .value("Basal", y(basal: segment.rate))) + .foregroundStyle(P.basal) + RuleMark(xStart: .value("Start", segment.start), xEnd: .value("End", segment.end), y: .value("Basal", y(basal: segment.rate))) + .foregroundStyle(P.basalEdge) + .lineStyle(StrokeStyle(lineWidth: 1.5)) + } + ForEach(Array(history.scheduledBasal.enumerated()), id: \.offset) { _, value in + RuleMark(xStart: .value("Start", value.start), xEnd: .value("End", value.end), y: .value("Scheduled", y(basal: value.rate))) + .foregroundStyle(P.basalScheduled) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [3, 3])) + } + + // Boluses over basal: solid for manual with a label, outlined for automatic + let bolusLabels = labelledBoluses + ForEach(history.boluses) { bolus in + if bolus.automatic { + RectangleMark(x: .value("Time", bolus.date), yStart: .value("Base", 0), yEnd: .value("Bolus", y(bolus: bolus.units)), width: .fixed(5)) + .foregroundStyle(P.insulin) + RectangleMark(x: .value("Time", bolus.date), yStart: .value("Base", 0.6), yEnd: .value("Bolus", max(0.6, y(bolus: bolus.units) - 0.6)), width: .fixed(2)) + .foregroundStyle(P.surfaceRaised) + } else { + RectangleMark(x: .value("Time", bolus.date), yStart: .value("Base", 0), yEnd: .value("Bolus", y(bolus: bolus.units)), width: .fixed(5)) + .foregroundStyle(P.insulin) + .annotation(position: .top, spacing: 2) { + if bolusLabels.contains(bolus.id) { + Text(LoopFormat.number(bolus.units, decimals: 1)) + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.insulinInk) + } + } + } + } + + // Now + if window.contains(now) { + RuleMark(x: .value("Now", now)) + .foregroundStyle(P.inkMuted) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [2, 3])) + } + + if let selection { + RuleMark(x: .value("Selected", selection)) + .foregroundStyle(P.ink.opacity(0.6)) + .lineStyle(StrokeStyle(lineWidth: 1)) + } + } + .chartXScale(domain: window.start...window.end) + .chartYScale(domain: 0...104) + .chartXAxis { + AxisMarks(values: DayAxis.quarterDayMarks(in: window)) { value in + AxisValueLabel { + if let date = value.as(Date.self) { + Text(DayAxis.hourLabel(date)) + } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.inkMuted) + } + } + .chartYAxis { + AxisMarks(position: .leading, values: unit.dayTicks.map { y(glucose: unit.mgdl($0)) }) { value in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel { + if let mapped = value.as(Double.self), let tick = unit.dayTicks.first(where: { abs(y(glucose: unit.mgdl($0)) - mapped) < 0.01 }) { + Text(tick.formatted()) + } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.inkMuted) + } + } + .chartOverlay { proxy in + ScrubOverlay(proxy: proxy, selection: $selection, clampTo: window) + } + .overlay(alignment: .top) { + if let selection { + ScrubCallout(rows: scrubRows(at: selection)) + .padding(.top, 2) + .allowsHitTesting(false) + } + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(accessibilitySummary) + } + + private func scrubRows(at date: Date) -> [ScrubCallout.Row] { + var rows: [ScrubCallout.Row] = [.init(label: nil, value: LoopFormat.time(date), color: P.ink)] + if let glucose = nearest(history.glucose.map { ($0.date, $0.mgdl) }, to: date, within: 10 * 60) { + rows.append(.init(label: NSLocalizedString("Glucose", comment: "Chart callout label for the glucose reading at the touched time"), value: "\(unit.format(glucose)) \(unit.unitName)", color: P.glucoseInk)) + } + if let iob = nearest(history.iob.map { ($0.date, $0.value) }, to: date, within: 10 * 60) { + rows.append(.init(label: NSLocalizedString("IOB", comment: "Abbreviation for insulin on board (active insulin)"), value: LoopFormat.doseUnits(iob), color: P.insulinInk)) + } + if let cob = nearest(history.cob.map { ($0.date, $0.value) }, to: date, within: 10 * 60) { + rows.append(.init(label: NSLocalizedString("COB", comment: "Abbreviation for carbs on board (active carbohydrate)"), value: LoopFormat.grams(cob), color: P.carbsInk)) + } + if let segment = LoopHistoryMath.basalRate(at: date, in: history.basal) { + let value = segment.kind == .suspended + ? NSLocalizedString("Suspended", comment: "Chart callout value: insulin delivery was suspended at the touched time") + : LoopFormat.rate(segment.rate) + rows.append(.init(label: NSLocalizedString("Basal", comment: "Chart callout label for the basal rate at the touched time"), value: value, color: P.ink)) + } + if let bolus = history.boluses.min(by: { abs($0.date.timeIntervalSince(date)) < abs($1.date.timeIntervalSince(date)) }), + abs(bolus.date.timeIntervalSince(date)) < 5 * 60 { + rows.append(.init(label: bolus.automatic + ? NSLocalizedString("Automatic bolus", comment: "Chart callout label for a bolus Loop delivered automatically near the touched time") + : NSLocalizedString("Bolus", comment: "Chart callout label for a bolus near the touched time"), + value: LoopFormat.doseUnits(bolus.units), color: P.insulinInk)) + } + return rows + } + + private var accessibilitySummary: String { + let day = LoopFormat.weekdayDay(window.start) + let bolus = LoopFormat.totalUnits(history.bolusUnits) + let basal = LoopFormat.totalUnits(history.basalUnits) + let carbs = LoopFormat.grams(history.carbGrams) + if let last = history.glucose.last { + return String(format: NSLocalizedString("Insulin timeline, %1$@, bolus %2$@, basal %3$@, carbs %4$@, latest glucose %5$@ %6$@", comment: "VoiceOver summary of the day's insulin timeline chart. (1: weekday and date; 2: bolus total, e.g. 12.5 U; 3: basal total; 4: carbs total, e.g. 140 g; 5: latest glucose value; 6: glucose unit, mmol/L or mg/dL)"), day, bolus, basal, carbs, unit.format(last.mgdl), unit.unitName) + } + return String(format: NSLocalizedString("Insulin timeline, %1$@, bolus %2$@, basal %3$@, carbs %4$@", comment: "VoiceOver summary of the day's insulin timeline chart with no glucose readings. (1: weekday and date; 2: bolus total, e.g. 12.5 U; 3: basal total; 4: carbs total, e.g. 140 g)"), day, bolus, basal, carbs) + } +} + +func nearest(_ values: [(Date, Double)], to date: Date, within limit: TimeInterval) -> Double? { + guard let best = values.min(by: { abs($0.0.timeIntervalSince(date)) < abs($1.0.timeIntervalSince(date)) }), + abs(best.0.timeIntervalSince(date)) <= limit else { + return nil + } + return best.1 +} + +// MARK: - Scrubbing + +/// Touch and hold then drag to scrub; a plain swipe still scrolls the page. +/// +/// A UIKit long-press recogniser is used because a SwiftUI long-press-then-drag gesture inside a table cell +/// takes every drag that starts on the chart, so the page couldn't scroll past it. +struct ScrubOverlay: View { + let proxy: ChartProxy + @Binding var selection: Date? + let clampTo: DateInterval + + var body: some View { + GeometryReader { geometry in + if #available(iOS 18.0, *) { + Color.clear + .contentShape(Rectangle()) + .gesture(ScrubPressRecognizer { location in + update(location, in: geometry) + } onEnd: { + selection = nil + }) + } else { + Color.clear + } + } + } + + private func update(_ location: CGPoint, in geometry: GeometryProxy) { + guard let frame = proxy.plotFrame else { return } + let origin = geometry[frame].origin + if let date: Date = proxy.value(atX: location.x - origin.x) { + selection = min(max(date, clampTo.start), clampTo.end) + } + } +} + +@available(iOS 18.0, *) +private struct ScrubPressRecognizer: UIGestureRecognizerRepresentable { + let onChange: (CGPoint) -> Void + let onEnd: () -> Void + + func makeUIGestureRecognizer(context: Context) -> UILongPressGestureRecognizer { + let recognizer = UILongPressGestureRecognizer() + recognizer.minimumPressDuration = 0.3 + recognizer.allowableMovement = 12 + return recognizer + } + + func handleUIGestureRecognizerAction(_ recognizer: UILongPressGestureRecognizer, context: Context) { + switch recognizer.state { + case .began, .changed: + onChange(context.converter.localLocation) + case .ended, .cancelled, .failed: + onEnd() + default: + break + } + } +} + +struct ScrubCallout: View { + struct Row: Hashable { + let label: String? + let value: String + let color: Color + } + + let rows: [Row] + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + ForEach(rows, id: \.self) { row in + HStack(spacing: LoopDesign.Space.s1) { + if let label = row.label { + Text(label).foregroundStyle(P.inkMuted) + } + Text(row.value).foregroundStyle(row.color).fontWeight(.semibold) + } + } + } + .font(LoopDesign.Typeface.footnote.monospacedDigit()) + .padding(.horizontal, LoopDesign.Space.s2) + .padding(.vertical, LoopDesign.Space.s1) + .background(P.surfaceRaised, in: RoundedRectangle(cornerRadius: LoopDesign.Radius.sm)) + .overlay(RoundedRectangle(cornerRadius: LoopDesign.Radius.sm).strokeBorder(P.separator)) + } +} + +// MARK: - Prediction + +/// The last three hours of readings and Loop's dashed prediction for the next three. +struct PredictionChartView: View { + let readings: [GlucosePoint] + let prediction: [GlucosePoint] + let unit: GlucoseUnitStyle + let targetBands: [TargetBand] + var now: Date = Date() + var height: CGFloat = 150 + + @State private var selection: Date? + + private var window: DateInterval { + DateInterval(start: now.addingTimeInterval(-3 * 3600), end: now.addingTimeInterval(3 * 3600)) + } + + private func clamp(_ mgdl: Double) -> Double { + min(max(unit.value(mgdl), unit.dayDomain.lowerBound), unit.dayDomain.upperBound) + } + + private var futurePrediction: [GlucosePoint] { + prediction.filter { $0.date >= now.addingTimeInterval(-5 * 60) && $0.date <= window.end } + } + + var body: some View { + Chart { + ForEach(Array(targetBands.enumerated()), id: \.offset) { _, band in + RectangleMark(xStart: .value("Start", band.start), xEnd: .value("End", band.end), + yStart: .value("Low", clamp(band.range.lowerBound)), yEnd: .value("High", clamp(band.range.upperBound))) + .foregroundStyle(P.targetBand) + } + ForEach(Array(readings.filter { window.contains($0.date) }.enumerated()), id: \.offset) { _, point in + PointMark(x: .value("Time", point.date), y: .value("Glucose", clamp(point.mgdl))) + .symbolSize(12) + .foregroundStyle(P.glucose) + } + ForEach(Array(futurePrediction.enumerated()), id: \.offset) { index, point in + LineMark(x: .value("Time", point.date), y: .value("Predicted", clamp(point.mgdl)), series: .value("Series", "prediction")) + .foregroundStyle(P.glucose) + .lineStyle(StrokeStyle(lineWidth: 1.5, dash: [4, 3])) + .annotation(position: .topTrailing, spacing: 0) { + if index == futurePrediction.count - 1 { + Text(unit.format(point.mgdl)) + .font(LoopDesign.Typeface.caption.weight(.semibold)) + .foregroundStyle(P.ink) + } + } + } + RuleMark(x: .value("Now", now)) + .foregroundStyle(P.inkMuted) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [2, 3])) + if let selection { + RuleMark(x: .value("Selected", selection)) + .foregroundStyle(P.ink.opacity(0.6)) + } + } + .frame(height: height) + .chartXScale(domain: window.start...window.end) + .chartYScale(domain: unit.dayDomain) + .chartXAxis { + AxisMarks(values: [window.start, now, window.end]) { value in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel { + if let date = value.as(Date.self) { + Text(abs(date.timeIntervalSince(now)) < 60 ? NSLocalizedString("now", comment: "Prediction chart x-axis label marking the current time") : LoopFormat.time(date)) + } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.inkMuted) + } + } + .chartYAxis { + AxisMarks(position: .leading, values: unit.dayTicks) { _ in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel().font(LoopDesign.Typeface.caption).foregroundStyle(P.inkMuted) + } + } + .chartOverlay { proxy in + ScrubOverlay(proxy: proxy, selection: $selection, clampTo: window) + } + .overlay(alignment: .top) { + if let selection { + ScrubCallout(rows: scrubRows(at: selection)).allowsHitTesting(false) + } + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(accessibilitySummary) + } + + private func scrubRows(at date: Date) -> [ScrubCallout.Row] { + var rows: [ScrubCallout.Row] = [.init(label: nil, value: LoopFormat.time(date), color: P.ink)] + let source = date <= now ? readings : prediction + if let value = nearest(source.map { ($0.date, $0.mgdl) }, to: date, within: 10 * 60) { + rows.append(.init(label: date <= now + ? NSLocalizedString("Glucose", comment: "Chart callout label for the glucose reading at the touched time") + : NSLocalizedString("Predicted", comment: "Prediction chart callout label for Loop's predicted glucose at the touched time"), + value: "\(unit.format(value)) \(unit.unitName)", color: P.glucoseInk)) + } + return rows + } + + private var accessibilitySummary: String { + guard let last = futurePrediction.last else { + return NSLocalizedString("Glucose prediction unavailable", comment: "VoiceOver label for the prediction chart when Loop has no prediction") + } + return String(format: NSLocalizedString("Loop predicts %1$@ %2$@ by %3$@", comment: "VoiceOver summary of the prediction chart. (1: predicted glucose value; 2: glucose unit, mmol/L or mg/dL; 3: time of the prediction)"), unit.format(last.mgdl), unit.unitName, LoopFormat.time(last.date)) + } +} + +// MARK: - IOB and COB + +/// Insulin and carbs on board over the same window, each against its own coloured axis. +struct IOBCOBChartView: View { + let iob: [TimedValue] + let cob: [TimedValue] + let window: DateInterval + var now: Date = Date() + var height: CGFloat = 140 + + @State private var selection: Date? + + private var iobMax: Double { max(1, (iob.map(\.value).max() ?? 0) * 1.1) } + private var iobMin: Double { min(0, (iob.map(\.value).min() ?? 0) * 1.1) } + private var cobMax: Double { max(10, (cob.map(\.value).max() ?? 0) * 1.1) } + + /// COB drawn on the IOB scale. + private func scaled(cob value: Double) -> Double { value / cobMax * iobMax } + + private var iobTicks: [Double] { + let step = Self.niceStep(iobMax / 2) + return stride(from: (iobMin / step).rounded(.down) * step, through: iobMax, by: step).map { $0 } + } + + private var cobTicks: [Double] { + let step = Self.niceStep(cobMax / 2) + return stride(from: 0, through: cobMax, by: step).map { $0 } + } + + static func niceStep(_ raw: Double) -> Double { + guard raw > 0 else { return 1 } + let magnitude = pow(10, floor(log10(raw))) + let normalized = raw / magnitude + let nice: Double = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10 + return nice * magnitude + } + + var body: some View { + Chart { + RuleMark(y: .value("Zero", 0)) + .foregroundStyle(P.inkMuted) + .lineStyle(StrokeStyle(lineWidth: 1)) + + ForEach(Array(cob.enumerated()), id: \.offset) { _, value in + AreaMark(x: .value("Time", value.date), yStart: .value("Base", 0), yEnd: .value("COB", scaled(cob: value.value)), series: .value("Series", "cob-fill")) + .foregroundStyle(P.carbs.opacity(0.14)) + LineMark(x: .value("Time", value.date), y: .value("COB", scaled(cob: value.value)), series: .value("Series", value.date > now ? "cob-projected" : "cob")) + .foregroundStyle(P.carbs) + .lineStyle(StrokeStyle(lineWidth: 1.5, dash: value.date > now ? [4, 3] : [])) + } + ForEach(Array(iob.enumerated()), id: \.offset) { _, value in + AreaMark(x: .value("Time", value.date), yStart: .value("Base", 0), yEnd: .value("IOB", value.value), series: .value("Series", "iob-fill")) + .foregroundStyle(P.insulin.opacity(0.14)) + LineMark(x: .value("Time", value.date), y: .value("IOB", value.value), series: .value("Series", value.date > now ? "iob-projected" : "iob")) + .foregroundStyle(P.insulin) + .lineStyle(StrokeStyle(lineWidth: 1.5, dash: value.date > now ? [4, 3] : [])) + } + if window.contains(now) { + RuleMark(x: .value("Now", now)) + .foregroundStyle(P.inkMuted) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [1, 3])) + } + if let selection { + RuleMark(x: .value("Selected", selection)).foregroundStyle(P.ink.opacity(0.6)) + } + } + .frame(height: height) + .chartXScale(domain: window.start...window.end) + .chartYScale(domain: iobMin...iobMax) + .chartXAxis { + AxisMarks(values: DayAxis.quarterDayMarks(in: window)) { value in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel { + if let date = value.as(Date.self) { Text(DayAxis.hourLabel(date)) } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.inkMuted) + } + } + .chartYAxis { + AxisMarks(position: .leading, values: iobTicks) { value in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel { + if let v = value.as(Double.self) { Text(v.formatted(.number.precision(.fractionLength(0...1)))) } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.insulinInk) + } + AxisMarks(position: .trailing, values: cobTicks.map { scaled(cob: $0) }) { value in + AxisValueLabel { + if let v = value.as(Double.self) { Text((v / iobMax * cobMax).formatted(.number.precision(.fractionLength(0)))) } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.carbsInk) + } + } + .chartOverlay { proxy in + ScrubOverlay(proxy: proxy, selection: $selection, clampTo: window) + } + .overlay(alignment: .top) { + if let selection { + ScrubCallout(rows: scrubRows(at: selection)).allowsHitTesting(false) + } + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(accessibilitySummary) + } + + private func scrubRows(at date: Date) -> [ScrubCallout.Row] { + var rows: [ScrubCallout.Row] = [.init(label: nil, value: LoopFormat.time(date), color: P.ink)] + if let value = nearest(iob.map { ($0.date, $0.value) }, to: date, within: 10 * 60) { + rows.append(.init(label: NSLocalizedString("IOB", comment: "Abbreviation for insulin on board (active insulin)"), value: LoopFormat.doseUnits(value), color: P.insulinInk)) + } + if let value = nearest(cob.map { ($0.date, $0.value) }, to: date, within: 10 * 60) { + rows.append(.init(label: NSLocalizedString("COB", comment: "Abbreviation for carbs on board (active carbohydrate)"), value: LoopFormat.grams(value), color: P.carbsInk)) + } + return rows + } + + private var accessibilitySummary: String { + let iobNow = nearest(iob.map { ($0.date, $0.value) }, to: now, within: 10 * 60) + let cobNow = nearest(cob.map { ($0.date, $0.value) }, to: now, within: 10 * 60) + let unknown = NSLocalizedString("unknown", comment: "VoiceOver value when active insulin or carbs at the current time isn't known") + return String(format: NSLocalizedString("Active insulin %1$@, active carbs %2$@", comment: "VoiceOver summary of the active insulin and carbs chart. (1: insulin on board, e.g. 1.25 U, or unknown; 2: carbs on board, e.g. 20 g, or unknown)"), iobNow.map(LoopFormat.doseUnits) ?? unknown, cobNow.map(LoopFormat.grams) ?? unknown) + } +} diff --git a/Loop/Redesign/DayDetailView.swift b/Loop/Redesign/DayDetailView.swift new file mode 100644 index 0000000000..d2ba0a11e7 --- /dev/null +++ b/Loop/Redesign/DayDetailView.swift @@ -0,0 +1,127 @@ +// +// DayDetailView.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI + +private typealias P = LoopDesign.Palette + +/// One full day on InsulinTimeline with IOB and COB under it, stepping a day at a time. +struct DayDetailView: View { + let provider: LoopHistoryProvider + + @State private var day: Date + @State private var history: DayHistory? + @State private var now = Date() + @State private var loadError: String? + + init(provider: LoopHistoryProvider, day: Date) { + self.provider = provider + _day = State(initialValue: Calendar.current.startOfDay(for: day)) + } + + private var window: DateInterval { + DateInterval(start: day, end: Calendar.current.date(byAdding: .day, value: 1, to: day)!) + } + + private var isToday: Bool { Calendar.current.isDate(day, inSameDayAs: now) } + + var body: some View { + ScrollView { + VStack(alignment: .leading, spacing: LoopDesign.Space.s6) { + dayStepper + if let history { + LoopCard { + CardHeader(title: NSLocalizedString("Insulin", comment: "Title of the day page card showing insulin, carbs and glucose on one timeline")) { + HStack(spacing: 4) { + Text(LoopFormat.totalUnits(history.totalUnits)).foregroundStyle(P.insulinInk) + Text("·") + Text(LoopFormat.grams(history.carbGrams)).foregroundStyle(P.carbsInk) + } + } + InsulinTimelineView(history: history, unit: provider.unitStyle, targetBands: provider.glucoseTargetBands(in: history.window), + now: now, height: 300) + DayTotalsTiles(history: history) + ChartLegend(items: DayTotalsTiles.legend) + if history.source == .health { + Text(NSLocalizedString("From Apple Health: Loop keeps 7 days, so this day has no temp basal or schedule detail.", comment: "Day page note when the day is older than Loop's 7-day history and was read from Apple Health")) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + if #available(iOS 18.0, *) { + Text(NSLocalizedString("Touch and hold a chart to see exact values.", comment: "Hint under the day page charts explaining how to scrub them")) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + } + LoopCard { + CardHeader(title: NSLocalizedString("Active insulin and carbs", comment: "Title of the day page card charting insulin and carbs on board")) + if history.iob.isEmpty && history.cob.isEmpty { + ChartPlaceholder(message: history.source == .health + ? NSLocalizedString("Loop only works out active insulin and carbs for the days it keeps", comment: "Day page placeholder for active insulin and carbs on a day older than Loop's 7-day history") + : NSLocalizedString("No active insulin or carbs on this day", comment: "Day page placeholder when there was no insulin or carbs on board all day")) + } else { + IOBCOBChartView(iob: history.iob, cob: history.cob, window: window, now: now) + } + ChartLegend(items: [ + LegendItem(swatch: .solid(P.insulin), label: NSLocalizedString("IOB (U, left)", comment: "Chart legend: insulin on board in units, on the left axis")), + LegendItem(swatch: .solid(P.carbs), label: NSLocalizedString("COB (g, right)", comment: "Chart legend: carbs on board in grams, on the right axis")), + LegendItem(swatch: .dash(P.inkMuted), label: NSLocalizedString("Projected", comment: "Chart legend: dashed lines show Loop's projection of insulin and carbs on board")), + ]) + } + } else if let loadError { + ChartPlaceholder(message: String(format: NSLocalizedString("Couldn't load this day: %1$@", comment: "Day page error when the day's history can't be read. (1: system error description)"), loadError)) + } else { + ProgressView() + .frame(maxWidth: .infinity, minHeight: 300) + } + } + .padding(LoopDesign.Space.s4) + } + .background(P.surface) + .navigationTitle(isToday ? NSLocalizedString("Today", comment: "Day page title when showing today") : LoopFormat.weekdayDay(day)) + .navigationBarTitleDisplayMode(.inline) + .task(id: day) { + now = Date() + let requestedWindow = window + history = nil + loadError = nil + do { + let result = try await provider.dayHistory(requestedWindow) + guard !Task.isCancelled, window == requestedWindow else { return } + history = result + } catch { + guard !Task.isCancelled, window == requestedWindow else { return } + loadError = error.localizedDescription + } + } + } + + private var dayStepper: some View { + HStack { + Button { + day = Calendar.current.date(byAdding: .day, value: -1, to: day)! + } label: { + Image(systemName: "chevron.left").frame(width: 44, height: 44) + } + .accessibilityLabel(NSLocalizedString("Previous day", comment: "Accessibility label for the day page button that steps back a day")) + Spacer() + Text(LoopFormat.day(day)) + .font(LoopDesign.Typeface.headline) + .foregroundStyle(P.ink) + Spacer() + Button { + day = Calendar.current.date(byAdding: .day, value: 1, to: day)! + } label: { + Image(systemName: "chevron.right").frame(width: 44, height: 44) + } + .disabled(isToday) + .accessibilityLabel(NSLocalizedString("Next day", comment: "Accessibility label for the day page button that steps forward a day")) + } + .font(.body.weight(.semibold)) + .foregroundStyle(P.accentInk) + } +} diff --git a/Loop/Redesign/LogbookScreen.swift b/Loop/Redesign/LogbookScreen.swift new file mode 100644 index 0000000000..52652a6e35 --- /dev/null +++ b/Loop/Redesign/LogbookScreen.swift @@ -0,0 +1,526 @@ +// +// LogbookScreen.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import LoopKit +import LoopKitUI + +private typealias P = LoopDesign.Palette + +/// One row of the logbook. +struct LogEntry: Identifiable { + enum Filter: String, CaseIterable, Identifiable { + case all = "All" + case bolus = "Bolus" + case basal = "Basal" + case carbs = "Carbs" + case loop = "Loop" + var id: String { rawValue } + + var title: String { + switch self { + case .all: return NSLocalizedString("All", comment: "Logbook filter chip: show every entry") + case .bolus: return NSLocalizedString("Bolus", comment: "Logbook filter chip: show only boluses") + case .basal: return NSLocalizedString("Basal", comment: "Logbook filter chip: show only basal changes") + case .carbs: return NSLocalizedString("Carbs", comment: "Logbook filter chip: show only carb entries") + case .loop: return NSLocalizedString("Loop", comment: "Logbook filter chip: show only what Loop did automatically (Loop is the app's name)") + } + } + } + + enum Action { + case deleteCarbs(StoredCarbEntry) + case deleteDose(DoseEntry) + } + + let id: String + let date: Date + let title: String + let subtitle: String + let amount: String + let amountColor: Color + let detail: String + let icon: String + let iconFill: Color + let filters: Set + var basalChanges: [BasalSegment] = [] + var edit: StoredCarbEntry? = nil + var delete: Action? = nil + + func matches(_ filter: Filter) -> Bool { + filter == .all || filters.contains(filter) + } +} + +struct LogDay: Identifiable { + let day: Date + let entries: [LogEntry] + let insulin: Double + let carbs: Double + var id: Date { day } +} + +@MainActor +final class LogbookModel: ObservableObject { + @Published private(set) var days: [LogDay] = [] + @Published private(set) var loaded = false + @Published var filter: LogEntry.Filter = .all + @Published var error: String? + @Published private(set) var loadError: String? + @Published private(set) var carbEditingAllowed = false + + let provider: LoopHistoryProvider + private var loadTask: Task? + + init(provider: LoopHistoryProvider) { + self.provider = provider + } + + func reload() { + loadTask?.cancel() + carbEditingAllowed = provider.allowsCarbEditing + loadError = nil + loadTask = Task { + do { + let result = try await Self.build(provider: provider) + guard !Task.isCancelled else { return } + self.days = result + } catch { + guard !Task.isCancelled else { return } + self.days = [] + self.loadError = error.localizedDescription + } + self.loaded = true + } + } + + func perform(_ action: LogEntry.Action) { + Task { + do { + switch action { + case .deleteCarbs(let entry): + guard provider.allowsCarbEditing else { return } + try await provider.delete(carb: entry) + case .deleteDose(let dose): try await provider.delete(dose: dose) + } + reload() + } catch { + self.error = error.localizedDescription + } + } + } + + // MARK: Building rows + + private static func build(provider: LoopHistoryProvider, now: Date = Date()) async throws -> [LogDay] { + let calendar = Calendar.current + let start = calendar.startOfDay(for: provider.localHistoryStart.addingTimeInterval(86400)) + let interval = DateInterval(start: start, end: now) + async let historyFetch = provider.dayHistory(interval, includeOnBoard: false) + async let pumpFetch = provider.pumpEvents(since: start) + let history = try await historyFetch + let pumpEvents = try await pumpFetch + let unit = provider.unitStyle + let canDelete = FeatureFlags.entryDeletionEnabled + + return LoopHistoryMath.days(in: interval).reversed().map { day in + var entries: [LogEntry] = [] + let inDay: (Date) -> Bool = { $0 >= day.start && $0 < day.end } + let carbsToday = history.carbs.filter { inDay($0.date) } + + for bolus in history.boluses where inDay(bolus.date) { + let glucose = glucoseContext(at: bolus.date, history.glucose, unit: unit, withTrend: bolus.automatic) + var parts = [bolus.automatic ? sourceLoop : sourceManual] + if !bolus.automatic, let meal = carbsToday.first(where: { abs($0.date.timeIntervalSince(bolus.date)) <= 15 * 60 }) { + parts.append(LoopFormat.grams(meal.grams)) + } + if let glucose { parts.append(glucose) } + if bolus.manuallyEntered { parts.append(NSLocalizedString("logged", comment: "Logbook bolus row detail: the dose was logged by hand rather than delivered by the pump")) } + entries.append(LogEntry( + id: "bolus-\(bolus.id)", date: bolus.date, + title: bolus.automatic + ? NSLocalizedString("Automatic bolus", comment: "Logbook row title: a bolus Loop delivered automatically") + : NSLocalizedString("Bolus", comment: "Logbook row title: a bolus"), + subtitle: joined(parts), + amount: LoopFormat.doseUnits(bolus.units), amountColor: P.insulinInk, + detail: LoopFormat.time(bolus.date), + icon: "plus", iconFill: P.insulin, + filters: bolus.automatic ? [.bolus, .loop] : [.bolus], + delete: canDelete && bolus.manuallyEntered ? bolus.dose.map { .deleteDose($0) } : nil)) + } + + for carb in carbsToday { + var parts = [carb.createdByLoop ? sourceManual : NSLocalizedString("Health", comment: "Logbook carb row detail: the entry came from Apple Health")] + if let food = carb.foodType, !food.isEmpty { parts.append(food) } + if let hours = carb.absorptionHours { parts.append(String(format: NSLocalizedString("absorbs over %1$@ h", comment: "Logbook carb row detail: carb absorption time in hours. (1: hours, e.g. 3 or 2.5)"), hours.formatted(.number.precision(.fractionLength(0...1))))) } + let editable = carb.createdByLoop && provider.allowsCarbEditing ? carb.entry : nil + entries.append(LogEntry( + id: "carbs-\(carb.id)", date: carb.date, + title: NSLocalizedString("Carbs", comment: "Logbook row title: a carb entry"), subtitle: joined(parts), + amount: LoopFormat.grams(carb.grams), amountColor: P.carbsInk, + detail: LoopFormat.time(carb.date), + icon: "fork.knife", iconFill: P.carbs, filters: [.carbs], + edit: editable, + delete: canDelete ? editable.map { .deleteCarbs($0) } : nil)) + } + + let segments = history.basal.compactMap { $0.clamped(to: day) } + let automaticTemps = segments.filter { $0.kind == .temp && $0.automatic } + if let latest = automaticTemps.last { + let net = automaticTemps.reduce(0) { $0 + $1.netUnits } + let count = automaticTemps.count + entries.append(LogEntry( + id: "basal-\(day.start.timeIntervalSince1970)", date: latest.start, + title: NSLocalizedString("Basal adjustments", comment: "Logbook row title summarising the temp basals Loop set in a day"), + subtitle: String.localizedStringWithFormat(NSLocalizedString("Loop · %lld changes · tap to list", comment: "Logbook basal adjustments row subtitle: how many temp basals Loop set in the day; tapping lists them. (1: number of changes)"), count), + amount: String(format: NSLocalizedString("%1$@ U", comment: "Format string for an amount of insulin in units. (1: amount)"), LoopFormat.signed(net, decimals: 1)), amountColor: P.insulinInk, + detail: NSLocalizedString("vs plan", comment: "Logbook basal adjustments row: the insulin amount is the difference from the scheduled basal"), + icon: "waveform.path.ecg", iconFill: P.basalEdge, filters: [.basal, .loop], + basalChanges: automaticTemps.reversed())) + } + for temp in segments where temp.kind == .temp && !temp.automatic { + entries.append(LogEntry( + id: "temp-\(temp.start.timeIntervalSince1970)", date: temp.start, + title: NSLocalizedString("Temp basal", comment: "Logbook row title: a temporary basal rate"), + subtitle: String(format: NSLocalizedString("Manual · %1$@", comment: "Logbook temp basal row subtitle: set by hand, then the rate and how long. (1: description, e.g. 0.50 U/h for 30m (scheduled 0.80))"), describe(temp)), + amount: LoopFormat.rate(temp.rate), amountColor: P.insulinInk, + detail: LoopFormat.time(temp.start), + icon: "waveform.path.ecg", iconFill: P.basalEdge, filters: [.basal])) + } + for suspend in segments where suspend.kind == .suspended { + var parts = [suspend.automatic ? sourceLoop : sourceManual, LoopFormat.duration(suspend.end.timeIntervalSince(suspend.start))] + if let glucose = glucoseContext(at: suspend.start, history.glucose, unit: unit, withTrend: false) { parts.append(glucose) } + entries.append(LogEntry( + id: "suspend-\(suspend.start.timeIntervalSince1970)", date: suspend.start, + title: NSLocalizedString("Basal suspended", comment: "Logbook row title: insulin delivery was suspended"), subtitle: joined(parts), + amount: String(format: NSLocalizedString("%1$@ U/h", comment: "Format string for an insulin rate in units per hour. (1: rate)"), LoopFormat.number(0, decimals: 0)), amountColor: P.ink, + detail: LoopFormat.time(suspend.start), + icon: "pause.fill", iconFill: P.statusWarning, + filters: suspend.automatic ? [.basal, .loop] : [.basal])) + } + + for event in pumpEvents where inDay(event.date) { + let title: String + switch event.kind { + // Site change and alarm names come from the pump plugin as it reports them. + case .siteChange(let name): title = name + case .alarm(let name): title = name + case .resume: title = NSLocalizedString("Basal resumed", comment: "Logbook row title: insulin delivery resumed after a suspend") + } + entries.append(LogEntry( + id: "pump-\(event.id)", date: event.date, + title: title, subtitle: NSLocalizedString("Pump", comment: "Logbook row subtitle: the event was reported by the insulin pump"), + amount: "", amountColor: P.ink, + detail: LoopFormat.time(event.date), + icon: "circle.dashed", iconFill: P.inkMuted.opacity(0.5), filters: [])) + } + + let insulin = segments.reduce(0) { $0 + $1.units } + history.boluses.filter { inDay($0.date) }.reduce(0) { $0 + $1.units } + return LogDay(day: day.start, entries: entries.sorted { $0.date > $1.date }, insulin: insulin, + carbs: carbsToday.reduce(0) { $0 + $1.grams }) + } + } + + private static var sourceLoop: String { + NSLocalizedString("Loop", comment: "Logbook row detail: Loop made this change automatically (Loop is the app's name)") + } + + private static var sourceManual: String { + NSLocalizedString("Manual", comment: "Logbook row detail: the user made this entry or change by hand") + } + + /// Row details are a list of independent facts ("Manual", "45 g", "glucose 7.5"), shown with a middle-dot separator. + private static func joined(_ parts: [String]) -> String { + parts.joined(separator: " · ") + } + + static func describe(_ segment: BasalSegment) -> String { + let rate = LoopFormat.rate(segment.rate) + let duration = LoopFormat.duration(segment.end.timeIntervalSince(segment.start)) + if let scheduled = segment.scheduledRate { + return String(format: NSLocalizedString("%1$@ for %2$@ (scheduled %3$@)", comment: "A temp basal: its rate, how long it ran and the scheduled rate it replaced. (1: rate, e.g. 0.50 U/h; 2: duration, e.g. 30m; 3: scheduled rate number, e.g. 0.80)"), rate, duration, LoopFormat.number(scheduled, decimals: 2)) + } + return String(format: NSLocalizedString("%1$@ for %2$@", comment: "A temp basal: its rate and how long it ran. (1: rate, e.g. 0.50 U/h; 2: duration, e.g. 30m)"), rate, duration) + } + + /// "glucose 7.5", or "glucose 11.0 rising" for Loop's own doses. + private static func glucoseContext(at date: Date, _ readings: [GlucosePoint], unit: GlucoseUnitStyle, withTrend: Bool) -> String? { + guard let reading = readings.last(where: { $0.date <= date.addingTimeInterval(60) }), date.timeIntervalSince(reading.date) <= 10 * 60 else { + return nil + } + let value = unit.format(reading.mgdl) + if withTrend, let earlier = readings.last(where: { $0.date <= reading.date.addingTimeInterval(-14 * 60) }), + reading.date.timeIntervalSince(earlier.date) <= 20 * 60 { + let perFifteen = (reading.mgdl - earlier.mgdl) / reading.date.timeIntervalSince(earlier.date) * 900 + if perFifteen > 10 { + return String(format: NSLocalizedString("glucose %1$@ rising", comment: "Logbook row detail: glucose when the dose was given, and rising. (1: glucose value, e.g. 11.0)"), value) + } else if perFifteen < -10 { + return String(format: NSLocalizedString("glucose %1$@ falling", comment: "Logbook row detail: glucose when the dose was given, and falling. (1: glucose value, e.g. 11.0)"), value) + } + } + return String(format: NSLocalizedString("glucose %1$@", comment: "Logbook row detail: glucose when the dose was given. (1: glucose value, e.g. 7.5)"), value) + } +} + +// MARK: - Screen + +struct LogbookView: View { + @StateObject private var model: LogbookModel + @State private var path: [Route] = [] + private let deviceManager: DeviceDataManager + + enum Route: Hashable { + case basal(String) + case editCarbs(CarbEditRoute) + } + + struct CarbEditRoute: Hashable { + let id = UUID() + let entry: StoredCarbEntry + + static func == (lhs: Self, rhs: Self) -> Bool { lhs.id == rhs.id } + func hash(into hasher: inout Hasher) { hasher.combine(id) } + } + + init(provider: LoopHistoryProvider, deviceManager: DeviceDataManager) { + _model = StateObject(wrappedValue: LogbookModel(provider: provider)) + self.deviceManager = deviceManager + } + + private var visibleDays: [LogDay] { + model.days.map { day in + LogDay(day: day.day, entries: day.entries.filter { $0.matches(model.filter) }, insulin: day.insulin, carbs: day.carbs) + } + } + + var body: some View { + NavigationStack(path: $path) { + List { + Section { + chips + .listRowInsets(EdgeInsets()) + .listRowBackground(Color.clear) + } + if let error = model.loadError { + Text(String(format: NSLocalizedString("Couldn't load Logbook: %1$@", comment: "Logbook error when its history can't be read. (1: system error description)"), error)).foregroundStyle(P.criticalInk) + Button(NSLocalizedString("Retry", comment: "Button to try loading the Logbook again")) { model.reload() } + } else if model.loaded && model.days.allSatisfy({ $0.entries.isEmpty }) { + Text(NSLocalizedString("Nothing logged in the last 7 days.", comment: "Logbook empty state when there are no entries at all")) + .foregroundStyle(P.inkMuted) + } + ForEach(visibleDays) { day in + Section { + if day.entries.isEmpty { + Text(model.filter != .all + ? NSLocalizedString("Nothing to show for this filter", comment: "Logbook day with no entries matching the selected filter") + : day.insulin > 0 + ? NSLocalizedString("Scheduled basal only", comment: "Logbook day where only the scheduled basal ran, with nothing else logged") + : NSLocalizedString("Nothing logged", comment: "Logbook day with no entries")) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + ForEach(day.entries) { entry in + row(entry) + } + } header: { + dayHeader(day) + } + } + Section { + EmptyView() + } footer: { + Text(NSLocalizedString("Loop keeps the last 7 days on this phone. Older doses and carbs are in Apple Health and on the Trends tab.", comment: "Logbook footer explaining why only 7 days are listed")) + } + } + .listStyle(.insetGrouped) + .scrollContentBackground(.hidden) + .background(P.surface) + .navigationTitle(NSLocalizedString("Logbook", comment: "Title of the Logbook tab")) + .refreshable { model.reload() } + .overlay { + if !model.loaded { ProgressView() } + } + .navigationDestination(for: Route.self) { route in + destination(route) + } + } + .onAppear { model.reload() } + .onReceive(NotificationCenter.default.publisher(for: .LoopDataUpdated).debounce(for: .seconds(2), scheduler: RunLoop.main)) { _ in + model.reload() + } + .alert(NSLocalizedString("Couldn't delete", comment: "Alert title when deleting a Logbook entry fails"), isPresented: Binding(get: { model.error != nil }, set: { if !$0 { model.error = nil } })) { + Button(NSLocalizedString("OK", comment: "Button to dismiss the Logbook delete error alert"), role: .cancel) {} + } message: { + Text(model.error ?? "") + } + } + + private var chips: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: LoopDesign.Space.s2) { + ForEach(LogEntry.Filter.allCases) { filter in + Button { + model.filter = filter + } label: { + Text(filter.title) + .font(LoopDesign.Typeface.footnote.weight(.semibold)) + .padding(.horizontal, 12) + .padding(.vertical, 6) + .foregroundStyle(model.filter == filter ? Color(uiColor: .systemBackground) : P.ink) + .background(model.filter == filter ? P.ink : P.surfaceSunken, in: Capsule()) + } + .buttonStyle(.plain) + .accessibilityAddTraits(model.filter == filter ? .isSelected : []) + } + } + .padding(.vertical, LoopDesign.Space.s1) + } + } + + private func dayHeader(_ day: LogDay) -> some View { + let calendar = Calendar.current + let date = LoopFormat.weekdayDay(day.day) + let title = calendar.isDateInToday(day.day) + ? String(format: NSLocalizedString("Today · %1$@", comment: "Logbook day header for today. (1: weekday and date, e.g. Sun 25 Oct)"), date) + : calendar.isDateInYesterday(day.day) + ? String(format: NSLocalizedString("Yesterday · %1$@", comment: "Logbook day header for yesterday. (1: weekday and date, e.g. Sat 24 Oct)"), date) + : date + return HStack(alignment: .firstTextBaseline) { + Text(title) + .font(LoopDesign.Typeface.headline) + .foregroundStyle(P.ink) + Spacer() + Text(LoopFormat.totalUnits(day.insulin)).foregroundStyle(P.insulinInk) + Text("·").foregroundStyle(P.inkMuted) + Text(LoopFormat.grams(day.carbs)).foregroundStyle(P.carbsInk) + } + .font(LoopDesign.Typeface.footnote) + .textCase(nil) + .accessibilityElement(children: .combine) + } + + @ViewBuilder + private func row(_ entry: LogEntry) -> some View { + let content = HStack(spacing: LoopDesign.Space.s3) { + IconTile(systemName: entry.icon, fill: entry.iconFill) + VStack(alignment: .leading, spacing: 2) { + Text(entry.title) + .font(LoopDesign.Typeface.body) + .foregroundStyle(P.ink) + Text(entry.subtitle) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + Spacer(minLength: LoopDesign.Space.s2) + VStack(alignment: .trailing, spacing: 2) { + if !entry.amount.isEmpty { + Text(entry.amount) + .font(LoopDesign.Typeface.body.weight(.semibold).monospacedDigit()) + .foregroundStyle(entry.amountColor) + } + Text(entry.detail) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + } + .accessibilityElement(children: .combine) + + if !entry.basalChanges.isEmpty { + NavigationLink(value: Route.basal(entry.id)) { content } + } else { + content + .swipeActions(edge: .trailing, allowsFullSwipe: false) { + if let action = entry.delete, canPerform(action) { + Button(role: .destructive) { model.perform(action) } label: { Label(NSLocalizedString("Delete", comment: "Swipe action to delete a Logbook entry"), systemImage: "trash") } + } + if let carb = entry.edit, model.carbEditingAllowed { + Button { + guard model.provider.allowsCarbEditing else { return } + path.append(.editCarbs(CarbEditRoute(entry: carb))) + } label: { Label(NSLocalizedString("Edit", comment: "Swipe action to edit a Logbook carb entry"), systemImage: "pencil") } + .tint(P.accent) + } + } + } + } + + private func canPerform(_ action: LogEntry.Action) -> Bool { + switch action { + case .deleteCarbs: return model.carbEditingAllowed + case .deleteDose: return true + } + } + + @ViewBuilder + private func destination(_ route: Route) -> some View { + switch route { + case .basal(let id): + if let entry = model.days.flatMap(\.entries).first(where: { $0.id == id }) { + BasalChangesList(changes: entry.basalChanges) + } + case .editCarbs(let route): + LogbookCarbEditor(entry: route.entry, deviceManager: deviceManager, provider: model.provider) { + path.removeAll() + model.reload() + } + } + } +} + +/// Own the draft independently of rows that refresh while the editor or its bolus screen is open. +private struct LogbookCarbEditor: View { + @StateObject private var viewModel: CarbEntryViewModel + let deviceManager: DeviceDataManager + let provider: LoopHistoryProvider + let dismiss: () -> Void + + init(entry: StoredCarbEntry, deviceManager: DeviceDataManager, provider: LoopHistoryProvider, dismiss: @escaping () -> Void) { + _viewModel = StateObject(wrappedValue: CarbEntryViewModel(delegate: deviceManager, originalCarbEntry: entry)) + self.deviceManager = deviceManager + self.provider = provider + self.dismiss = dismiss + } + + var body: some View { + CarbEntryView(viewModel: viewModel) + .environmentObject(deviceManager.displayGlucosePreference) + .environment(\.dismissAction, dismiss) + .navigationTitle(NSLocalizedString("Edit Carb Entry", comment: "Title of the screen for editing a carb entry from the Logbook")) + .navigationBarTitleDisplayMode(.inline) + .onAppear { if !provider.allowsCarbEditing { dismiss() } } + // Loop posts this from its data queue; SwiftUI faults on publishers that emit off the main thread. + .onReceive(NotificationCenter.default.publisher(for: .LoopDataUpdated).receive(on: RunLoop.main)) { _ in + if !provider.allowsCarbEditing { dismiss() } + } + } +} + +/// Every basal change Loop made in a day. +struct BasalChangesList: View { + let changes: [BasalSegment] + + var body: some View { + List(Array(changes.enumerated()), id: \.offset) { _, change in + HStack { + VStack(alignment: .leading, spacing: 2) { + Text(LoopFormat.time(change.start)) + .font(LoopDesign.Typeface.body) + Text(LogbookModel.describe(change)) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + Spacer() + Text(String(format: NSLocalizedString("%1$@ U", comment: "Format string for an amount of insulin in units. (1: amount)"), LoopFormat.signed(change.netUnits))) + .font(LoopDesign.Typeface.body.weight(.semibold).monospacedDigit()) + .foregroundStyle(P.insulinInk) + } + .accessibilityElement(children: .combine) + } + .navigationTitle(NSLocalizedString("Basal adjustments", comment: "Title of the list of every temp basal Loop set in a day")) + .navigationBarTitleDisplayMode(.inline) + } +} diff --git a/Loop/Redesign/LoopDesign.swift b/Loop/Redesign/LoopDesign.swift new file mode 100644 index 0000000000..c23b2a1ba7 --- /dev/null +++ b/Loop/Redesign/LoopDesign.swift @@ -0,0 +1,319 @@ +// +// LoopDesign.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import UIKit + +/// The tokens from the Loop design system (`design/project/tokens.json`). +/// +/// Quantity colours reuse Loop's existing assets (`glucose`, `insulin`, `carbs`, `fresh`, `warning`, `accent`) +/// so a DerivedAssetsOverride still recolours them. Grounds and text map onto the iOS system colours they +/// were taken from; the rest are colour sets in DerivedAssetsBase.xcassets named after their token. +enum LoopDesign { + + enum Palette { + // Grounds + static let surface = Color(uiColor: .systemGroupedBackground) + static let surfaceRaised = Color(uiColor: .secondarySystemGroupedBackground) + static let surfaceSunken = Color(uiColor: .systemGray5) + static let controlThumb = Color("control-thumb") + static let separator = Color(uiColor: .opaqueSeparator) + static let grid = Color(uiColor: .systemGray5) + + // Text + static let ink = Color(uiColor: .label) + static let inkMuted = Color("ink-muted") + static let accent = Color("accent") + static let accentInk = Color("accent-ink") + static let onFill = Color.black + + // Quantities + static let glucose = Color("glucose") + static let glucoseInk = Color("glucose-ink") + static let targetBand = Color("target-band") + static let agpOuter = Color("agp-outer") + static let agpInner = Color("agp-inner") + static let insulin = Color("insulin") + static let insulinInk = Color("insulin-ink") + static let basal = Color("basal") + static let basalEdge = Color("basal-edge") + static let basalScheduled = inkMuted + static let carbs = Color("carbs") + static let carbsInk = Color("carbs-ink") + + // Time in range ladder, top to bottom + static let rangeVeryHigh = Color("range-very-high") + static let rangeHigh = Color("range-high") + static let rangeIn = Color("range-in") + static let rangeLow = Color("range-low") + static let rangeVeryLow = Color("range-very-low") + + // Loop state + static let statusAutomated = Color("fresh") + static let statusWarning = Color("warning") + static let statusCritical = Color("status-critical") + static let criticalInk = Color("critical-ink") + } + + enum Space { + static let s1: CGFloat = 4 + static let s2: CGFloat = 8 + static let s3: CGFloat = 12 + static let s4: CGFloat = 16 + static let s6: CGFloat = 24 + static let s8: CGFloat = 32 + } + + enum Radius { + static let sm: CGFloat = 6 + static let md: CGFloat = 10 + static let lg: CGFloat = 14 + } + + /// Text styles follow Dynamic Type; the large numbers are fixed sizes in SF Pro Rounded with tabular figures. + enum Typeface { + static let glucoseHero = Font.system(size: 64, weight: .bold, design: .rounded).monospacedDigit() + static let statValue = Font.system(.title, design: .rounded).weight(.semibold).monospacedDigit() + static let statValueSmall = Font.system(.title3, design: .rounded).weight(.semibold).monospacedDigit() + static let title = Font.title.bold() + static let headline = Font.headline + static let body = Font.body + static let subhead = Font.subheadline + static let footnote = Font.footnote + static let caption = Font.caption2.weight(.medium).monospacedDigit() + } +} + +// MARK: - Card + +struct LoopCard: View { + var padding: CGFloat = LoopDesign.Space.s4 + @ViewBuilder var content: Content + + var body: some View { + VStack(alignment: .leading, spacing: LoopDesign.Space.s3) { + content + } + .padding(padding) + .frame(maxWidth: .infinity, alignment: .leading) + .background(LoopDesign.Palette.surfaceRaised, in: RoundedRectangle(cornerRadius: LoopDesign.Radius.lg, style: .continuous)) + } +} + +/// A card title with an optional trailing detail or action, as on every card in the mock-ups. +struct CardHeader: View { + let title: String + @ViewBuilder var trailing: Trailing + + var body: some View { + HStack(alignment: .firstTextBaseline) { + Text(title) + .font(LoopDesign.Typeface.headline) + .foregroundStyle(LoopDesign.Palette.ink) + .accessibilityAddTraits(.isHeader) + Spacer(minLength: LoopDesign.Space.s2) + trailing + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(LoopDesign.Palette.inkMuted) + } + } +} + +extension CardHeader where Trailing == EmptyView { + init(title: String) { + self.init(title: title) { EmptyView() } + } +} + +// MARK: - Legend + +struct LegendItem: Identifiable { + enum Swatch { + case solid(Color) + case outline(Color) + case dash(Color) + case dot(Color) + case basal + } + + let id = UUID() + let swatch: Swatch + let label: String +} + +struct ChartLegend: View { + let items: [LegendItem] + + var body: some View { + FlowLayout(spacing: LoopDesign.Space.s3, lineSpacing: LoopDesign.Space.s1) { + ForEach(items) { item in + HStack(spacing: LoopDesign.Space.s1) { + swatch(item.swatch) + Text(item.label) + } + .accessibilityElement(children: .combine) + } + } + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(LoopDesign.Palette.inkMuted) + } + + @ViewBuilder + private func swatch(_ swatch: LegendItem.Swatch) -> some View { + switch swatch { + case .solid(let color): + RoundedRectangle(cornerRadius: 2).fill(color).frame(width: 10, height: 10) + case .outline(let color): + RoundedRectangle(cornerRadius: 2).strokeBorder(color, lineWidth: 1.5).frame(width: 10, height: 10) + case .dash(let color): + Path { path in + path.move(to: CGPoint(x: 0, y: 1)) + path.addLine(to: CGPoint(x: 14, y: 1)) + } + .stroke(color, style: StrokeStyle(lineWidth: 2, dash: [4, 2])) + .frame(width: 14, height: 2) + case .dot(let color): + Circle().fill(color).frame(width: 8, height: 8) + case .basal: + VStack(spacing: 0) { + Rectangle().fill(LoopDesign.Palette.basalEdge).frame(height: 2) + Rectangle().fill(LoopDesign.Palette.basal) + } + .frame(width: 10, height: 10) + .clipShape(RoundedRectangle(cornerRadius: 2)) + } + } +} + +/// Wraps its children onto new lines, for legends and chips. +struct FlowLayout: Layout { + var spacing: CGFloat + var lineSpacing: CGFloat + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + let width = proposal.width ?? .infinity + var x: CGFloat = 0, y: CGFloat = 0, lineHeight: CGFloat = 0, maxX: CGFloat = 0 + for subview in subviews { + let size = subview.sizeThatFits(.unspecified) + if x > 0 && x + size.width > width { + x = 0 + y += lineHeight + lineSpacing + lineHeight = 0 + } + x += size.width + spacing + maxX = max(maxX, x - spacing) + lineHeight = max(lineHeight, size.height) + } + return CGSize(width: maxX, height: y + lineHeight) + } + + func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { + var x = bounds.minX, y = bounds.minY, lineHeight: CGFloat = 0 + for subview in subviews { + let size = subview.sizeThatFits(.unspecified) + if x > bounds.minX && x + size.width > bounds.maxX { + x = bounds.minX + y += lineHeight + lineSpacing + lineHeight = 0 + } + subview.place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size)) + x += size.width + spacing + lineHeight = max(lineHeight, size.height) + } + } +} + +/// A row that stacks vertically at accessibility text sizes, so tiles and buttons keep their numbers on one line. +struct AdaptiveRow: View { + @Environment(\.dynamicTypeSize) private var typeSize + var spacing: CGFloat = LoopDesign.Space.s2 + @ViewBuilder var content: Content + + var body: some View { + let layout = typeSize.isAccessibilitySize + ? AnyLayout(VStackLayout(alignment: .leading, spacing: spacing)) + : AnyLayout(HStackLayout(spacing: spacing)) + layout { content } + } +} + +// MARK: - Pills and tiles + +struct StatusPill: View { + let text: String + var dot: Color? = nil + + var body: some View { + HStack(spacing: LoopDesign.Space.s1) { + if let dot { + Circle().fill(dot).frame(width: 8, height: 8) + } + Text(text) + .lineLimit(1) + } + .font(LoopDesign.Typeface.footnote.weight(.medium)) + .foregroundStyle(LoopDesign.Palette.ink) + .padding(.horizontal, 10) + .padding(.vertical, 5) + .background(LoopDesign.Palette.surfaceSunken, in: Capsule()) + } +} + +/// A small sunken tile with a label over a value, as used under the hero and the timeline. +struct ValueTile: View { + let label: String + @ViewBuilder var value: Value + + var body: some View { + VStack(alignment: .leading, spacing: 2) { + Text(label) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(LoopDesign.Palette.inkMuted) + .lineLimit(1) + .minimumScaleFactor(0.7) + .allowsTightening(true) + // A value with a long unit ("0.04 単位") shrinks to fit rather than breaking mid-word. + value + .lineLimit(1) + .minimumScaleFactor(0.6) + } + .padding(LoopDesign.Space.s3) + .frame(maxWidth: .infinity, minHeight: 64, maxHeight: .infinity, alignment: .topLeading) + .background(LoopDesign.Palette.surfaceSunken, in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md, style: .continuous)) + .accessibilityElement(children: .combine) + } +} + +/// The square icon tile at the start of logbook rows. +struct IconTile: View { + let systemName: String + let fill: Color + + var body: some View { + Image(systemName: systemName) + .font(.system(size: 13, weight: .bold)) + .foregroundStyle(LoopDesign.Palette.onFill) + .frame(width: 28, height: 28) + .background(fill, in: RoundedRectangle(cornerRadius: LoopDesign.Radius.sm, style: .continuous)) + .accessibilityHidden(true) + } +} + +/// A message in place of a chart that has nothing to draw, saying why. +struct ChartPlaceholder: View { + let message: String + var height: CGFloat = 120 + + var body: some View { + Text(message) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(LoopDesign.Palette.inkMuted) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity, minHeight: height) + .background(LoopDesign.Palette.surfaceSunken.opacity(0.5), in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md)) + } +} diff --git a/Loop/Redesign/LoopHistoryMath.swift b/Loop/Redesign/LoopHistoryMath.swift new file mode 100644 index 0000000000..5e75c93474 --- /dev/null +++ b/Loop/Redesign/LoopHistoryMath.swift @@ -0,0 +1,346 @@ +// +// LoopHistoryMath.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import Foundation + +/// Pure calculations behind the Trends and Logbook screens. Nothing here touches a store. +enum LoopHistoryMath { + + // MARK: Glucose statistics + + struct GlucoseStats: Equatable { + let count: Int + let meanMgdl: Double + let sdMgdl: Double + /// Coefficient of variation, 0–1. + let cv: Double + /// Glucose management indicator, as a percentage (Bergenstal 2018). + let gmiPercent: Double + var gmiMmolMol: Double { (gmiPercent - 2.152) * 10.929 } + } + + static func glucoseStats(_ points: [GlucosePoint]) -> GlucoseStats? { + guard points.count >= 2 else { return nil } + let values = points.map(\.mgdl) + let mean = values.reduce(0, +) / Double(values.count) + let variance = values.reduce(0) { $0 + pow($1 - mean, 2) } / Double(values.count - 1) + let sd = variance.squareRoot() + return GlucoseStats(count: values.count, meanMgdl: mean, sdMgdl: sd, cv: sd / mean, gmiPercent: 3.31 + 0.02392 * mean) + } + + /// The share of the period with CGM readings, assuming one reading every 5 minutes. + static func cgmActiveFraction(_ points: [GlucosePoint], over interval: DateInterval) -> Double { + let expected = interval.duration / 300 + guard expected > 0 else { return 0 } + return min(1, Double(points.count) / expected) + } + + // MARK: Time in range + + enum RangeBand: Int, CaseIterable, Identifiable { + case veryHigh, high, inRange, low, veryLow + + var id: Int { rawValue } + + var name: String { + switch self { + case .veryHigh: return NSLocalizedString("Very high", comment: "Time-in-range band name: glucose above 250 mg/dL (13.9 mmol/L)") + case .high: return NSLocalizedString("High", comment: "Time-in-range band name: glucose 181–250 mg/dL (10.1–13.9 mmol/L)") + case .inRange: return NSLocalizedString("In range", comment: "Time-in-range band name: glucose 70–180 mg/dL (3.9–10.0 mmol/L)") + case .low: return NSLocalizedString("Low", comment: "Time-in-range band name: glucose 54–69 mg/dL (3.0–3.8 mmol/L)") + case .veryLow: return NSLocalizedString("Very low", comment: "Time-in-range band name: glucose below 54 mg/dL (3.0 mmol/L)") + } + } + + /// Consensus thresholds, in the person's unit. + /// Numbers go through the user's locale ("3,9–10,0" in German); the symbols are not words, so they stay in code. + func thresholds(_ unit: GlucoseUnitStyle) -> String { + let d = unit.isMmol ? 1 : 0 + func n(_ value: Double) -> String { LoopFormat.number(value, decimals: d) } + switch (self, unit.isMmol) { + case (.veryHigh, true): return "> " + n(13.9) + case (.high, true): return n(10.1) + "–" + n(13.9) + case (.inRange, true): return n(3.9) + "–" + n(10.0) + case (.low, true): return n(3.0) + "–" + n(3.8) + case (.veryLow, true): return "< " + n(3.0) + case (.veryHigh, false): return "> " + n(250) + case (.high, false): return n(181) + "–" + n(250) + case (.inRange, false): return n(70) + "–" + n(180) + case (.low, false): return n(54) + "–" + n(69) + case (.veryLow, false): return "< " + n(54) + } + } + + static func band(for mgdl: Double) -> RangeBand { + switch mgdl { + case ..<54: return .veryLow + case ..<70: return .low + case ...180: return .inRange + case ...250: return .high + default: return .veryHigh + } + } + } + + /// Fractions (0–1) per band, in ladder order. Empty input gives all zeros. + static func timeInRange(_ points: [GlucosePoint]) -> [RangeBand: Double] { + var counts: [RangeBand: Int] = [:] + for point in points { + counts[RangeBand.band(for: point.mgdl), default: 0] += 1 + } + let total = Double(points.count) + return Dictionary(uniqueKeysWithValues: RangeBand.allCases.map { band in + (band, total > 0 ? Double(counts[band] ?? 0) / total : 0) + }) + } + + /// Whole-number percentages that add up to 100 (largest remainder), so the labels never sum to 99 or 101. + static func roundedPercentages(_ fractions: [RangeBand: Double]) -> [RangeBand: Int] { + let raw = RangeBand.allCases.map { (band: $0, value: (fractions[$0] ?? 0) * 100) } + let total = raw.reduce(0) { $0 + $1.value } + guard total > 0 else { return Dictionary(uniqueKeysWithValues: RangeBand.allCases.map { ($0, 0) }) } + var floors = raw.map { (band: $0.band, floor: Int($0.value.rounded(.down)), remainder: $0.value - $0.value.rounded(.down)) } + var missing = Int(total.rounded()) - floors.reduce(0) { $0 + $1.floor } + for index in floors.indices.sorted(by: { floors[$0].remainder > floors[$1].remainder }) where missing > 0 { + floors[index].floor += 1 + missing -= 1 + } + return Dictionary(uniqueKeysWithValues: floors.map { ($0.band, $0.floor) }) + } + + // MARK: AGP + + struct AGPSlot: Equatable { + /// Minutes after midnight at the start of the slot. + let minute: Int + let p5: Double + let p25: Double + let p50: Double + let p75: Double + let p95: Double + } + + /// Readings folded onto one day in `slotMinutes` slots, as mg/dL percentiles. Slots with fewer than 3 readings are skipped. + static func agp(_ points: [GlucosePoint], slotMinutes: Int = 15, calendar: Calendar = .current) -> [AGPSlot] { + var slots: [Int: [Double]] = [:] + for point in points { + let parts = calendar.dateComponents([.hour, .minute], from: point.date) + let minute = (parts.hour ?? 0) * 60 + (parts.minute ?? 0) + slots[minute / slotMinutes, default: []].append(point.mgdl) + } + return slots.keys.sorted().compactMap { key in + let values = slots[key]!.sorted() + guard values.count >= 3 else { return nil } + return AGPSlot(minute: key * slotMinutes, + p5: percentile(values, 0.05), p25: percentile(values, 0.25), p50: percentile(values, 0.5), + p75: percentile(values, 0.75), p95: percentile(values, 0.95)) + } + } + + /// Linear-interpolated percentile of sorted values. + static func percentile(_ sorted: [Double], _ p: Double) -> Double { + guard !sorted.isEmpty else { return .nan } + let position = p * Double(sorted.count - 1) + let lower = Int(position.rounded(.down)), upper = Int(position.rounded(.up)) + let weight = position - Double(lower) + return sorted[lower] * (1 - weight) + sorted[upper] * weight + } + + /// The number of distinct calendar days with readings. + static func daysWithReadings(_ points: [GlucosePoint], calendar: Calendar = .current) -> Int { + Set(points.map { calendar.startOfDay(for: $0.date) }).count + } + + // MARK: Days + + /// Midnight-to-midnight intervals covering `interval`, oldest first, the last one cut off at `interval.end`. + static func days(in interval: DateInterval, calendar: Calendar = .current) -> [DateInterval] { + var result: [DateInterval] = [] + var start = calendar.startOfDay(for: interval.start) + while start < interval.end { + guard let next = calendar.date(byAdding: .day, value: 1, to: start) else { break } + result.append(DateInterval(start: max(start, interval.start), end: min(next, interval.end))) + start = next + } + return result + } + + struct DayTotal: Equatable, Identifiable { + let day: Date + let basal: Double + let bolus: Double + /// False for a day still in progress, so its partial total doesn't pull per-day averages down. + var isComplete = true + var id: Date { day } + var total: Double { basal + bolus } + } + + /// The days per-day insulin figures average over: days with insulin, leaving out a day still in progress + /// unless no complete day has any. + static func averagingDays(_ totals: [DayTotal]) -> [DayTotal] { + let recorded = totals.filter { $0.total > 0 } + let complete = recorded.filter(\.isComplete) + return complete.isEmpty ? recorded : complete + } + + /// One source for the summary, legend and chart rule, before any weekly aggregation. + static func averageDailyInsulin(_ totals: [DayTotal]) -> Double { + let days = averagingDays(totals) + guard !days.isEmpty else { return 0 } + return days.reduce(0) { $0 + $1.total } / Double(days.count) + } + + /// Averages daily totals by calendar week (Monday start), for periods past 30 days. + static func weekly(_ totals: [DayTotal], calendar: Calendar = .current) -> [DayTotal] { + var cal = calendar + cal.firstWeekday = 2 + let groups = Dictionary(grouping: totals) { cal.dateInterval(of: .weekOfYear, for: $0.day)?.start ?? $0.day } + return groups.keys.sorted().map { week in + let days = groups[week]! + let n = Double(days.count) + return DayTotal(day: week, basal: days.reduce(0) { $0 + $1.basal } / n, bolus: days.reduce(0) { $0 + $1.bolus } / n) + } + } + + // MARK: Basal + + struct ScheduleValue { + let start: Date + let end: Date + let rate: Double + } + + /// A basal record from the pump: scheduled delivery, a temp basal or a suspend. + struct BasalDelivery { + let start: Date + let end: Date + /// U/h; 0 for a suspend. + let rate: Double + let kind: BasalSegment.Kind + let automatic: Bool + } + + /// Delivered basal over `window` from the pump's records (the latest-starting one wins where they overlap). + /// + /// Gaps remain unknown: a scheduled rate alone is not evidence of delivery. + static func basalSegments(window: DateInterval, schedule: [ScheduleValue], deliveries temps: [BasalDelivery]) -> [BasalSegment] { + var cuts = Set([window.start, window.end]) + for value in schedule { + if window.contains(value.start) { cuts.insert(value.start) } + if window.contains(value.end) { cuts.insert(value.end) } + } + for temp in temps { + if window.contains(temp.start) { cuts.insert(temp.start) } + if window.contains(temp.end) { cuts.insert(temp.end) } + } + let sorted = cuts.sorted() + let sortedTemps = temps.sorted { $0.start < $1.start } + var segments: [BasalSegment] = [] + for (a, b) in zip(sorted, sorted.dropFirst()) where b > a { + let mid = a.addingTimeInterval(b.timeIntervalSince(a) / 2) + let scheduled = schedule.first { $0.start <= mid && mid < $0.end }?.rate + let segment: BasalSegment + if let temp = sortedTemps.last(where: { $0.start <= mid && mid < $0.end }) { + segment = BasalSegment(start: a, end: b, rate: temp.kind == .suspended ? 0 : temp.rate, scheduledRate: scheduled, + kind: temp.kind, automatic: temp.automatic) + } else { + continue + } + if let last = segments.last, last.end == segment.start, last.rate == segment.rate, last.kind == segment.kind, + last.scheduledRate == segment.scheduledRate, last.automatic == segment.automatic { + segments[segments.count - 1] = BasalSegment(start: last.start, end: segment.end, rate: last.rate, + scheduledRate: last.scheduledRate, kind: last.kind, automatic: last.automatic) + } else { + segments.append(segment) + } + } + return segments + } + + /// Basal rate at a moment, from delivered segments. + static func basalRate(at date: Date, in segments: [BasalSegment]) -> BasalSegment? { + segments.last { $0.start <= date && date < $0.end } + } + + // MARK: Loop modes + + struct LoopRun { + let date: Date + let succeeded: Bool + let error: String? + } + + struct ModeChange: Codable, Equatable { + let date: Date + let closedLoop: Bool + } + + /// Splits `interval` into closed, limited and open stretches. + /// + /// Each 5-minute slot is open when closed loop was switched off (from `modeChanges`), closed when Loop completed a + /// run in the 15 minutes before the slot ends, and limited otherwise. Before the first mode change the setting is + /// unknown, so the result starts at the later of `coverageStart` and the first mode change. + static func loopModeSpans(interval: DateInterval, runs: [LoopRun], modeChanges: [ModeChange], coverageStart: Date?, + recency: TimeInterval = 15 * 60, slot: TimeInterval = 5 * 60) -> [LoopModeSpan] { + guard let coverageStart, let firstChange = modeChanges.map(\.date).min() else { return [] } + let start = max(interval.start, coverageStart, firstChange) + guard interval.end > start else { return [] } + + let sortedRuns = runs.sorted { $0.date < $1.date } + let changes = modeChanges.sorted { $0.date < $1.date } + var spans: [LoopModeSpan] = [] + var runIndex = 0 + var lastSuccess: Date? = nil + var lastError: String? = nil + var changeIndex = 0 + var closedSetting: Bool? = nil + + var t = start + while t < interval.end { + let slotEnd = min(t.addingTimeInterval(slot), interval.end) + while runIndex < sortedRuns.count && sortedRuns[runIndex].date <= slotEnd { + let run = sortedRuns[runIndex] + if run.succeeded { + lastSuccess = run.date + lastError = nil + } else { + lastError = run.error ?? lastError + } + runIndex += 1 + } + while changeIndex < changes.count && changes[changeIndex].date <= slotEnd { + closedSetting = changes[changeIndex].closedLoop + changeIndex += 1 + } + + let mode: LoopModeSpan.Mode + let cause: String? + if closedSetting == false { + mode = .open + cause = NSLocalizedString("Closed loop off", comment: "Reason shown for a stretch of time when Loop was in open loop because closed loop was turned off") + } else if let lastSuccess, slotEnd.timeIntervalSince(lastSuccess) <= recency { + mode = .closed + cause = nil + } else { + mode = .limited + cause = lastError ?? NSLocalizedString("Loop didn't run", comment: "Reason shown for a stretch of time when Loop did not complete a run and recorded no error") + } + + if let last = spans.last, last.mode == mode, last.cause == cause, last.end == t { + spans[spans.count - 1] = LoopModeSpan(start: last.start, end: slotEnd, mode: mode, cause: cause) + } else { + spans.append(LoopModeSpan(start: t, end: slotEnd, mode: mode, cause: cause)) + } + t = slotEnd + } + return spans + } + + static func duration(of mode: LoopModeSpan.Mode, in spans: [LoopModeSpan]) -> TimeInterval { + spans.filter { $0.mode == mode }.reduce(0) { $0 + $1.duration } + } +} diff --git a/Loop/Redesign/LoopHistoryModels.swift b/Loop/Redesign/LoopHistoryModels.swift new file mode 100644 index 0000000000..7ac4196c87 --- /dev/null +++ b/Loop/Redesign/LoopHistoryModels.swift @@ -0,0 +1,304 @@ +// +// LoopHistoryModels.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import Foundation +import HealthKit +import LoopKit + +/// Plain value types the redesigned screens draw from. Glucose is kept in mg/dL and converted only for display, +/// so the statistics don't depend on the display unit. + +struct GlucosePoint: Equatable { + let date: Date + let mgdl: Double +} + +struct BolusEvent: Equatable, Identifiable { + let id: String + let date: Date + let units: Double + /// Issued by Loop (automatic bolus) rather than by the person. + let automatic: Bool + /// Logged in Loop by hand rather than delivered by the pump; these can be deleted. + let manuallyEntered: Bool + /// Kept so a manually entered dose can be deleted from the dose store. + var dose: DoseEntry? = nil + + static func == (lhs: BolusEvent, rhs: BolusEvent) -> Bool { + lhs.id == rhs.id && lhs.date == rhs.date && lhs.units == rhs.units && lhs.automatic == rhs.automatic + } +} + +struct BasalSegment: Equatable { + enum Kind: Equatable { + /// The scheduled rate, with no temp basal running. + case scheduled + /// A temp basal, set by Loop or by hand. + case temp + case suspended + } + + let start: Date + let end: Date + /// The rate actually delivered, in U/h. + let rate: Double + /// The profile rate at the time, in U/h, if known. + let scheduledRate: Double? + let kind: Kind + let automatic: Bool + + var hours: Double { end.timeIntervalSince(start) / 3600 } + var units: Double { rate * hours } + /// Units delivered above (positive) or below (negative) the schedule. + var netUnits: Double { + guard let scheduledRate else { return 0 } + return (rate - scheduledRate) * hours + } + + func clamped(to interval: DateInterval) -> BasalSegment? { + let s = max(start, interval.start), e = min(end, interval.end) + guard e > s else { return nil } + return BasalSegment(start: s, end: e, rate: rate, scheduledRate: scheduledRate, kind: kind, automatic: automatic) + } +} + +struct ScheduledBasalPoint: Equatable { + let start: Date + let end: Date + let rate: Double +} + +/// The correction range over part of a chart, in mg/dL. +struct TargetBand: Equatable { + let start: Date + let end: Date + let range: ClosedRange +} + +struct CarbEvent: Equatable, Identifiable { + let id: String + let date: Date + let grams: Double + let absorptionHours: Double? + let foodType: String? + let createdByLoop: Bool + /// Kept so the entry can be edited or deleted. + var entry: StoredCarbEntry? = nil + + static func == (lhs: CarbEvent, rhs: CarbEvent) -> Bool { + lhs.id == rhs.id && lhs.date == rhs.date && lhs.grams == rhs.grams + } +} + +struct TimedValue: Equatable { + let date: Date + let value: Double +} + +struct PumpLogEvent: Equatable, Identifiable { + enum Kind: Equatable { + case siteChange(String) + case alarm(String) + case resume + } + + let id: String + let date: Date + let kind: Kind +} + +/// Everything known about one day (or any window up to 48 hours), for InsulinTimeline and the Now screen. +struct DayHistory { + var window: DateInterval + var glucose: [GlucosePoint] = [] + var boluses: [BolusEvent] = [] + var basal: [BasalSegment] = [] + var scheduledBasal: [ScheduledBasalPoint] = [] + var carbs: [CarbEvent] = [] + var iob: [TimedValue] = [] + var cob: [TimedValue] = [] + /// Where the data came from, so older days can say they are missing Loop's own detail. + var source: HistorySource = .loop + + var bolusUnits: Double { boluses.reduce(0) { $0 + $1.units } } + var basalUnits: Double { basal.reduce(0) { $0 + $1.units } } + var carbGrams: Double { carbs.reduce(0) { $0 + $1.grams } } + var totalUnits: Double { bolusUnits + basalUnits } +} + +enum HistorySource { + /// Loop's own stores: manual versus automatic, temp basals and the schedule are all known. + case loop + /// Apple Health, for days older than Loop keeps. Doses are split into basal and bolus only. + case health +} + +/// One stretch of the period in a single loop mode. +struct LoopModeSpan: Equatable { + enum Mode: Equatable { + case closed + case limited + case open + } + + let start: Date + let end: Date + let mode: Mode + let cause: String? + + var duration: TimeInterval { end.timeIntervalSince(start) } +} + +// MARK: - Glucose unit + +struct GlucoseUnitStyle: Equatable { + let isMmol: Bool + + init(unit: HKUnit) { + isMmol = unit == .millimolesPerLiter + } + + init(isMmol: Bool) { + self.isMmol = isMmol + } + + static let mgdlPerMmol = 18.0182 + + var unitName: String { isMmol ? "mmol/L" : "mg/dL" } + + func value(_ mgdl: Double) -> Double { isMmol ? mgdl / Self.mgdlPerMmol : mgdl } + func mgdl(_ displayValue: Double) -> Double { isMmol ? displayValue * Self.mgdlPerMmol : displayValue } + + func format(_ mgdl: Double) -> String { + isMmol ? LoopFormat.number(mgdl / Self.mgdlPerMmol, decimals: 1) : LoopFormat.number(mgdl, decimals: 0) + } + + /// Fixed chart scales from the design: 2–20 mmol/L on day views, 0–22 on AGP. + var dayDomain: ClosedRange { isMmol ? 2...20 : 36...360 } + var agpDomain: ClosedRange { isMmol ? 0...22 : 0...400 } + var dayTicks: [Double] { isMmol ? [4, 10, 16] : [70, 180, 300] } + var agpTicks: [Double] { isMmol ? [0, 4, 10, 16, 22] : [0, 70, 180, 250, 400] } +} + +// MARK: - Formatting + +enum LoopFormat { + /// A number in the user's locale, e.g. "7.3" or "7,3", with no grouping so values read like Loop's own screens. + static func number(_ value: Double, decimals: Int) -> String { + value.formatted(.number.precision(.fractionLength(decimals)).grouping(.never)) + } + + static func doseUnits(_ units: Double) -> String { + String(format: NSLocalizedString("%1$@ U", comment: "Format string for an amount of insulin in units. (1: amount)"), number(units, decimals: 2)) + } + + static func totalUnits(_ units: Double) -> String { + String(format: NSLocalizedString("%1$@ U", comment: "Format string for an amount of insulin in units. (1: amount)"), number(units, decimals: 1)) + } + + static func rate(_ rate: Double) -> String { + String(format: NSLocalizedString("%1$@ U/h", comment: "Format string for an insulin rate in units per hour. (1: rate)"), number(rate, decimals: 2)) + } + + static func grams(_ grams: Double) -> String { + String(format: NSLocalizedString("%1$@ g", comment: "Format string for an amount of carbohydrate in grams. (1: grams)"), number(grams, decimals: 0)) + } + + static func signed(_ value: Double, decimals: Int = 2) -> String { + let s = number(abs(value), decimals: decimals) + if abs(value) < pow(10, -Double(decimals)) / 2 { return "+" + s } + return (value < 0 ? "−" : "+") + s + } + + static func time(_ date: Date) -> String { + date.formatted(date: .omitted, time: .shortened) + } + + /// "25 Oct 2026" + static func day(_ date: Date) -> String { + date.formatted(.dateTime.day().month(.abbreviated).year()) + } + + /// "Sun 25 Oct" + static func weekdayDay(_ date: Date) -> String { + date.formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated)) + } + + /// "12 – 25 Oct 2026", "28 Sep – 25 Oct 2026", "20 Dec 2025 – 2 Jan 2026", in the user's locale. + static func range(_ start: Date, _ end: Date, calendar: Calendar = .current) -> String { + if calendar.isDate(start, inSameDayAs: end) { + return day(end) + } + let formatter = DateIntervalFormatter() + formatter.calendar = calendar + formatter.dateTemplate = "dMMMy" + return formatter.string(from: start, to: end) + } + + /// "13d 11h", "9h 45m", "40m" in English; abbreviated in the user's language. + static func duration(_ interval: TimeInterval) -> String { + let minutes = Int((interval / 60).rounded()) + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .abbreviated + formatter.allowedUnits = minutes >= 1440 ? [.day, .hour] : minutes >= 60 ? [.hour, .minute] : [.minute] + formatter.zeroFormattingBehavior = .dropAll + return formatter.string(from: TimeInterval(minutes * 60)) ?? "" + } + + /// "2m", "1h 5m": how long ago, for the status pill. + static func ago(_ date: Date, now: Date = Date()) -> String { + let minutes = max(0, Int(now.timeIntervalSince(date) / 60)) + let formatter = DateComponentsFormatter() + formatter.unitsStyle = .abbreviated + formatter.allowedUnits = minutes >= 1440 ? [.day, .hour] : minutes >= 60 ? [.hour, .minute] : [.minute] + formatter.zeroFormattingBehavior = minutes == 0 ? .pad : .dropAll + return formatter.string(from: TimeInterval(minutes * 60)) ?? "" + } +} + +// MARK: - Store conversion boundaries + +extension BolusEvent { + init?(dose: DoseEntry, in interval: DateInterval) { + guard dose.type == .bolus, dose.startDate >= interval.start, dose.startDate < interval.end else { return nil } + self.init(id: dose.syncIdentifier ?? "\(dose.startDate.timeIntervalSince1970)", date: dose.startDate, + units: dose.unitsInDeliverableIncrements, automatic: dose.automatic ?? false, + manuallyEntered: dose.manuallyEntered, dose: dose) + } +} + +extension LoopHistoryMath.BasalDelivery { + init?(dose: DoseEntry) { + let kind: BasalSegment.Kind + switch dose.type { + case .basal: kind = .scheduled + case .tempBasal: kind = .temp + case .suspend: kind = .suspended + default: return nil + } + let hours = dose.endDate.timeIntervalSince(dose.startDate) / 3600 + guard hours > 0 else { return nil } + self.init(start: dose.startDate, end: dose.endDate, + rate: kind == .suspended ? 0 : dose.unitsInDeliverableIncrements / hours, + kind: kind, automatic: dose.automatic ?? (kind == .temp)) + } +} + +extension BasalSegment { + init?(healthSample sample: HKQuantitySample, in interval: DateInterval) { + let hours = sample.endDate.timeIntervalSince(sample.startDate) / 3600 + guard hours > 0 else { return nil } + let scheduled = (sample.metadata?["com.loopkit.InsulinKit.MetadataKeyScheduledBasalRate"] as? HKQuantity)? + .doubleValue(for: DoseEntry.unitsPerHour) + let segment = BasalSegment(start: sample.startDate, end: sample.endDate, + rate: sample.quantity.doubleValue(for: .internationalUnit()) / hours, + scheduledRate: scheduled, kind: .temp, + automatic: (sample.metadata?["com.loopkit.InsulinKit.MetadataKeyAutomaticallyIssued"] as? NSNumber)?.boolValue ?? false) + guard let clamped = segment.clamped(to: interval) else { return nil } + self = clamped + } +} diff --git a/Loop/Redesign/LoopHistoryProvider.swift b/Loop/Redesign/LoopHistoryProvider.swift new file mode 100644 index 0000000000..d1525d8eb6 --- /dev/null +++ b/Loop/Redesign/LoopHistoryProvider.swift @@ -0,0 +1,434 @@ +// +// LoopHistoryProvider.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import Foundation +import HealthKit +import LoopKit +import LoopCore +import os.log + +/// Reads glucose, insulin, carbs and loop runs for the redesigned screens. +/// +/// Loop keeps `LOOP_LOCAL_CACHE_DURATION_DAYS` (7) days in its own stores. Inside that window everything comes from +/// those stores, so manual and automatic doses, temp basals and the schedule are known. Older days come from Apple +/// Health, which has glucose, carbs and insulin split only into basal and bolus. +final class LoopHistoryProvider { + + private let deviceManager: DeviceDataManager + private let log = OSLog(category: "LoopHistoryProvider") + + init(deviceManager: DeviceDataManager) { + self.deviceManager = deviceManager + } + + var unitStyle: GlucoseUnitStyle { + GlucoseUnitStyle(unit: deviceManager.displayGlucosePreference.unit) + } + + /// Match the classic carb editor's eligibility rule, including mode changes while a screen is open. + var allowsCarbEditing: Bool { + deviceManager.automaticDosingEnabled || !FeatureFlags.simpleBolusCalculatorEnabled + } + + /// The start of what Loop keeps locally. + var localHistoryStart: Date { + Date().addingTimeInterval(-Bundle.main.localCacheDuration) + } + + var glucoseTargetRange: ClosedRange? { + guard let schedule = deviceManager.loopManager.settings.effectiveGlucoseTargetRangeSchedule() else { return nil } + let range = schedule.quantityRange(at: Date()) + return range.lowerBound.doubleValue(for: .milligramsPerDeciliter)...range.upperBound.doubleValue(for: .milligramsPerDeciliter) + } + + /// The correction range schedule across `interval`, with any preset or pre-meal range over the time it runs, + /// as the classic glucose chart draws it. + func glucoseTargetBands(in interval: DateInterval) -> [TargetBand] { + let settings = deviceManager.loopManager.settings + guard let schedule = settings.glucoseTargetRangeSchedule else { return [] } + func mgdl(_ range: ClosedRange) -> ClosedRange { + range.lowerBound.doubleValue(for: .milligramsPerDeciliter)...range.upperBound.doubleValue(for: .milligramsPerDeciliter) + } + var bands = schedule.quantityBetween(start: interval.start, end: interval.end).map { + TargetBand(start: max($0.startDate, interval.start), end: min($0.endDate, interval.end), range: mgdl($0.value)) + } + // Pre-meal goes last so it wins where both run, as in LoopSettings.effectiveGlucoseTargetRangeSchedule. + for override in [settings.scheduleOverride, settings.preMealOverride].compactMap({ $0 }) { + guard let target = override.settings.targetRange, + let active = override.activeInterval.intersection(with: interval), active.duration > 0 else { continue } + bands = bands.flatMap { band -> [TargetBand] in + var pieces: [TargetBand] = [] + if band.start < active.start { + pieces.append(TargetBand(start: band.start, end: min(band.end, active.start), range: band.range)) + } + if band.end > active.end { + pieces.append(TargetBand(start: max(band.start, active.end), end: band.end, range: band.range)) + } + return pieces + } + [TargetBand(start: active.start, end: active.end, range: mgdl(target))] + } + return bands.sorted { $0.start < $1.start } + } + + // MARK: - Days + + /// Everything in `window`; IOB and COB only when asked, as they are the slowest part. + func dayHistory(_ window: DateInterval, includeOnBoard: Bool = true) async throws -> DayHistory { + var history = DayHistory(window: window) + let boundary = localHistoryStart + + if window.end > boundary { + let local = DateInterval(start: max(window.start, boundary), end: window.end) + async let glucose = localGlucose(local) + async let insulin = localInsulin(local) + async let carbs = localCarbs(local) + history.glucose = try await glucose + (history.boluses, history.basal, history.scheduledBasal) = try await insulin + history.carbs = try await carbs + if includeOnBoard { + async let iob = localIOB(local) + async let cob = localCOB(local) + history.iob = try await iob + history.cob = try await cob + } + } + + if window.start < boundary { + let older = DateInterval(start: window.start, end: min(window.end, boundary)) + async let glucose = healthGlucose(older) + async let insulin = healthInsulin(older) + async let carbs = healthCarbs(older) + let (boluses, basal) = try await insulin + history.glucose = try await glucose + history.glucose + history.boluses = boluses + history.boluses + history.basal = basal + history.basal + history.carbs = try await carbs + history.carbs + if window.end <= boundary { + history.source = .health + } + } + try Task.checkCancellation() + return history + } + + /// CGM readings for any period, local and Health combined. + func glucose(_ interval: DateInterval) async throws -> [GlucosePoint] { + let boundary = localHistoryStart + var points: [GlucosePoint] = [] + if interval.start < boundary { + points += try await healthGlucose(DateInterval(start: interval.start, end: min(interval.end, boundary))) + } + if interval.end > boundary { + points += try await localGlucose(DateInterval(start: max(interval.start, boundary), end: interval.end)) + } + return points + } + + // MARK: - Loop runs + + /// Fetch each snapshot independently: overlapping reloads must not append the same anchored page twice. + func loopRuns() async throws -> (runs: [LoopHistoryMath.LoopRun], coverageStart: Date?) { + var anchor: DosingDecisionStore.QueryAnchor? + var runs: [LoopHistoryMath.LoopRun] = [] + while true { + let page: (DosingDecisionStore.QueryAnchor, [StoredDosingDecision]) = try await withCheckedThrowingContinuation { continuation in + deviceManager.dosingDecisionStore.executeDosingDecisionQuery(fromQueryAnchor: anchor, limit: 1000) { result in + switch result { + case .success(let anchor, let decisions): continuation.resume(returning: (anchor, decisions)) + case .failure(let error): continuation.resume(throwing: error) + } + } + } + try Task.checkCancellation() + anchor = page.0 + runs += page.1.filter { $0.reason == "loop" }.map { decision in + LoopHistoryMath.LoopRun(date: decision.date, succeeded: decision.errors.isEmpty, + error: decision.errors.first.map { Self.describe(issue: $0.id) }) + } + if page.1.count < 1000 { break } + } + runs = runs.filter { $0.date >= localHistoryStart }.sorted { $0.date < $1.date } + return (runs, runs.first?.date) + } + + /// "glucoseTooOld" → "Glucose too old". Loop's own issue ids are localised; any other id falls back to the + /// id split into English words. + static func describe(issue id: String) -> String { + switch id { + case "configurationError": return NSLocalizedString("Configuration error", comment: "Reason Loop could not run: its settings are incomplete") + case "connectionError": return NSLocalizedString("Connection error", comment: "Reason Loop could not run: no connected devices, or a device connection failed") + case "missingDataError": return NSLocalizedString("Missing data error", comment: "Reason Loop could not run: data it needs was missing") + case "glucoseTooOld": return NSLocalizedString("Glucose too old", comment: "Reason Loop could not run: the latest glucose reading was too old") + case "invalidFutureGlucose": return NSLocalizedString("Invalid future glucose", comment: "Reason Loop could not run: a glucose reading had a timestamp in the future") + case "pumpDataTooOld": return NSLocalizedString("Pump data too old", comment: "Reason Loop could not run: the latest pump data was too old") + case "recommendationExpired": return NSLocalizedString("Recommendation expired", comment: "Reason Loop could not run: its dosing recommendation expired before it was used") + case "pumpSuspended": return NSLocalizedString("Pump suspended", comment: "Reason Loop could not run: insulin delivery on the pump was suspended") + case "pumpManagerError": return NSLocalizedString("Pump manager error", comment: "Reason Loop could not run: the pump reported an error") + case "unknownError": return NSLocalizedString("Unknown error", comment: "Reason Loop could not run: an unexpected error") + default: break + } + var words: [String] = [] + var current = "" + for character in id { + if character.isUppercase, !current.isEmpty { + words.append(current) + current = "" + } + current.append(character) + } + words.append(current) + let sentence = words.joined(separator: " ").lowercased() + return sentence.prefix(1).uppercased() + sentence.dropFirst() + } + + // MARK: - Pump events + + func pumpEvents(since start: Date) async throws -> [PumpLogEvent] { + try await withCheckedThrowingContinuation { continuation in + deviceManager.doseStore.getPumpEventValues(since: start) { result in + let events: [PersistedPumpEvent] + switch result { + case .success(let fetched): events = fetched + case .failure(let error): + continuation.resume(throwing: error) + return + } + let items: [PumpLogEvent] = events.compactMap { event in + let id = event.objectIDURL.absoluteString + switch event.type { + case .replaceComponent(let component)?: + let name: String + switch component { + case .pump: name = NSLocalizedString("Pod changed", comment: "Pump event in the history: the pump or pod was replaced") + case .reservoir: name = NSLocalizedString("Reservoir changed", comment: "Pump event in the history: the insulin reservoir was replaced") + case .infusionSet: name = NSLocalizedString("Infusion set changed", comment: "Pump event in the history: the infusion set was replaced") + } + return PumpLogEvent(id: id, date: event.date, kind: .siteChange(name)) + case .rewind?: + return PumpLogEvent(id: id, date: event.date, kind: .siteChange(NSLocalizedString("Reservoir rewound", comment: "Pump event in the history: the pump rewound its reservoir"))) + case .prime?: + return PumpLogEvent(id: id, date: event.date, kind: .siteChange(NSLocalizedString("Primed", comment: "Pump event in the history: the pump primed the tubing or cannula"))) + case .alarm?: + return PumpLogEvent(id: id, date: event.date, kind: .alarm(event.title ?? NSLocalizedString("Pump alarm", comment: "Pump event in the history: an alarm whose pump gave no title"))) + default: + return nil + } + } + continuation.resume(returning: items) + } + } + } + + // MARK: - Editing + + func delete(carb entry: StoredCarbEntry) async throws { + try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + deviceManager.loopManager.deleteCarbEntry(entry) { result in + switch result { + case .success: continuation.resume() + case .failure(let error): continuation.resume(throwing: error) + } + } + } + } + + func delete(dose: DoseEntry) async throws { + try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + deviceManager.doseStore.deleteDose(dose) { error in + if let error { + continuation.resume(throwing: error) + } else { + continuation.resume() + } + } + } + } + + // MARK: - Loop's stores + + private func localGlucose(_ interval: DateInterval) async throws -> [GlucosePoint] { + do { + let samples = try await deviceManager.glucoseStore.getGlucoseSamples(start: interval.start, end: interval.end) + return samples + .filter { !$0.isDisplayOnly } + .map { GlucosePoint(date: $0.startDate, mgdl: $0.quantity.doubleValue(for: .milligramsPerDeciliter)) } + } catch { + os_log("Glucose fetch failed: %{public}@", log: log, type: .error, String(describing: error)) + throw error + } + } + + private func localInsulin(_ interval: DateInterval) async throws -> ([BolusEvent], [BasalSegment], [ScheduledBasalPoint]) { + let doses: [DoseEntry] = try await withCheckedThrowingContinuation { continuation in + deviceManager.doseStore.getNormalizedDoseEntries(start: interval.start, end: interval.end) { result in + switch result { + case .success(let doses): + continuation.resume(returning: doses) + case .failure(let error): + os_log("Dose fetch failed: %{public}@", log: self.log, type: .error, String(describing: error)) + continuation.resume(throwing: error) + } + } + } + + let boluses = doses.compactMap { BolusEvent(dose: $0, in: interval) } + + let scheduleValues = deviceManager.loopManager.basalRateScheduleApplyingOverrideHistory? + .between(start: interval.start, end: interval.end) ?? [] + let schedule = scheduleValues.map { LoopHistoryMath.ScheduleValue(start: $0.startDate, end: $0.endDate, rate: $0.value) } + let deliveries = doses.compactMap { LoopHistoryMath.BasalDelivery(dose: $0) } + let now = Date() + let window = DateInterval(start: interval.start, end: max(interval.start, min(interval.end, now))) + // Totals count pump records, as classic Loop does; an unreported gap is not confirmed delivery. + let basal = window.duration > 0 ? LoopHistoryMath.basalSegments(window: window, schedule: schedule, deliveries: deliveries) : [] + let scheduled = schedule.map { ScheduledBasalPoint(start: max($0.start, interval.start), end: min($0.end, interval.end), rate: $0.rate) } + return (boluses, basal, scheduled) + } + + private func localCarbs(_ interval: DateInterval) async throws -> [CarbEvent] { + do { + let entries = try await deviceManager.carbStore.getCarbEntries(start: interval.start, end: interval.end) + return entries.map { entry in + CarbEvent(id: entry.syncIdentifier ?? "\(entry.startDate.timeIntervalSince1970)", + date: entry.startDate, + grams: entry.quantity.doubleValue(for: .gram()), + absorptionHours: entry.absorptionTime.map { $0 / 3600 }, + foodType: entry.foodType, + createdByLoop: entry.createdByCurrentApp, + entry: entry) + } + } catch { + os_log("Carb fetch failed: %{public}@", log: log, type: .error, String(describing: error)) + throw error + } + } + + private func localIOB(_ interval: DateInterval) async throws -> [TimedValue] { + try await withCheckedThrowingContinuation { continuation in + deviceManager.doseStore.getInsulinOnBoardValues(start: interval.start, end: interval.end, basalDosingEnd: nil) { result in + switch result { + case .success(let values): continuation.resume(returning: values.map { TimedValue(date: $0.startDate, value: $0.value) }) + case .failure(let error): continuation.resume(throwing: error) + } + } + } + } + + private func localCOB(_ interval: DateInterval) async throws -> [TimedValue] { + try await withCheckedThrowingContinuation { continuation in + deviceManager.carbStore.getCarbsOnBoardValues(start: interval.start, end: interval.end, effectVelocities: nil) { result in + switch result { + case .success(let values): continuation.resume(returning: values.map { TimedValue(date: $0.startDate, value: $0.quantity.doubleValue(for: .gram())) }) + case .failure(let error): continuation.resume(throwing: error) + } + } + } + } + + // MARK: - Apple Health + + private func healthSamples(_ type: HKQuantityType, _ interval: DateInterval, options: HKQueryOptions = .strictStartDate) async throws -> [HKQuantitySample] { + guard interval.duration > 0 else { return [] } + let log = self.log + return try await withCheckedThrowingContinuation { continuation in + let predicate = HKQuery.predicateForSamples(withStart: interval.start, end: interval.end, options: options) + let sort = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: true) + let query = HKSampleQuery(sampleType: type, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: [sort]) { _, samples, error in + if let error { + os_log("Health query for %{public}@ failed: %{public}@", log: log, type: .error, type.identifier, String(describing: error)) + continuation.resume(throwing: error) + } else { + continuation.resume(returning: (samples as? [HKQuantitySample]) ?? []) + } + } + deviceManager.healthStore.execute(query) + } + } + + /// Several apps can write the same CGM reading to Health; keep one reading per 2½ minutes. + private func healthGlucose(_ interval: DateInterval) async throws -> [GlucosePoint] { + let samples = try await healthSamples(HKQuantityType(.bloodGlucose), interval) + var points: [GlucosePoint] = [] + let own = HKSource.default().bundleIdentifier + for sample in samples where !sample.isDisplayOnly + && (FeatureFlags.observeHealthKitGlucoseSamplesFromOtherApps || sample.sourceRevision.source.bundleIdentifier == own) { + if let last = points.last, sample.startDate.timeIntervalSince(last.date) < 150 { continue } + points.append(GlucosePoint(date: sample.startDate, mgdl: sample.quantity.doubleValue(for: .milligramsPerDeciliter))) + } + return points + } + + private func healthInsulin(_ interval: DateInterval) async throws -> ([BolusEvent], [BasalSegment]) { + let samples = try await healthSamples(HKQuantityType(.insulinDelivery), interval, options: []) + var boluses: [BolusEvent] = [] + var basal: [BasalSegment] = [] + let own = HKSource.default().bundleIdentifier + for sample in samples where FeatureFlags.observeHealthKitDoseSamplesFromOtherApps || sample.sourceRevision.source.bundleIdentifier == own { + let units = sample.quantity.doubleValue(for: .internationalUnit()) + let reason = (sample.metadata?[HKMetadataKeyInsulinDeliveryReason] as? NSNumber)?.intValue + let automatic = (sample.metadata?["com.loopkit.InsulinKit.MetadataKeyAutomaticallyIssued"] as? NSNumber)?.boolValue ?? false + if reason == HKInsulinDeliveryReason.basal.rawValue { + if let segment = BasalSegment(healthSample: sample, in: interval) { + basal.append(segment) + } + } else if sample.startDate >= interval.start && sample.startDate < interval.end { + boluses.append(BolusEvent(id: sample.uuid.uuidString, date: sample.startDate, units: units, automatic: automatic, manuallyEntered: false)) + } + } + return (boluses, basal) + } + + private func healthCarbs(_ interval: DateInterval) async throws -> [CarbEvent] { + let samples = try await healthSamples(HKQuantityType(.dietaryCarbohydrates), interval) + let own = HKSource.default().bundleIdentifier + return samples + .filter { FeatureFlags.observeHealthKitCarbSamplesFromOtherApps || $0.sourceRevision.source.bundleIdentifier == own } + .map { sample in + CarbEvent(id: sample.uuid.uuidString, date: sample.startDate, grams: sample.quantity.doubleValue(for: .gram()), + absorptionHours: nil, foodType: sample.metadata?[HKMetadataKeyFoodType] as? String, + createdByLoop: sample.sourceRevision.source.bundleIdentifier == own) + } + } +} + +// MARK: - Loop mode history + +/// Records when closed loop is switched on and off, because Loop's stored runs don't say which mode they ran in. +/// The Trends screen can only call time "open loop" from the first record on. +final class LoopModeHistory { + static let shared = LoopModeHistory() + + private let defaults: UserDefaults + private let key = "com.loopkit.Loop.redesign.loopModeChanges" + private let maximumAge: TimeInterval = .days(100) + + init(defaults: UserDefaults = .standard) { + self.defaults = defaults + } + + var changes: [LoopHistoryMath.ModeChange] { + guard let data = defaults.data(forKey: key), + let changes = try? JSONDecoder().decode([LoopHistoryMath.ModeChange].self, from: data) else { + return [] + } + return changes + } + + func record(closedLoop: Bool, at date: Date = Date()) { + var changes = self.changes + guard changes.last?.closedLoop != closedLoop else { return } + changes.append(.init(date: date, closedLoop: closedLoop)) + // Keep the last change before the retention window: it establishes the mode at its start. + let cutoff = date.addingTimeInterval(-maximumAge) + if let anchor = changes.lastIndex(where: { $0.date < cutoff }), anchor > 0 { + changes.removeFirst(anchor) + } + if let data = try? JSONEncoder().encode(changes) { + defaults.set(data, forKey: key) + } + } +} diff --git a/Loop/Redesign/MainTabBarController.swift b/Loop/Redesign/MainTabBarController.swift new file mode 100644 index 0000000000..c0556dc916 --- /dev/null +++ b/Loop/Redesign/MainTabBarController.swift @@ -0,0 +1,98 @@ +// +// MainTabBarController.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import UIKit +import SwiftUI +import WidgetKit +import LoopCore + +/// Whether Loop shows the redesigned interface (tabs: Now, Trends, Logbook, Settings) or the classic status screen. +enum LoopInterfacePreference { + private static let key = "com.loopkit.Loop.redesign.enabled" + + static let didChange = Notification.Name("LoopInterfacePreferenceDidChange") + + static var useRedesign: Bool { + get { UserDefaults.standard.object(forKey: key) as? Bool ?? true } + set { + guard newValue != useRedesign else { return } + UserDefaults.standard.set(newValue, forKey: key) + syncToExtensions() + NotificationCenter.default.post(name: didChange, object: nil) + } + } + + /// Copies the setting to the app group, where the widget and Live Activity read it, and redraws both. + static func syncToExtensions() { + guard let shared = UserDefaults.appGroup, shared.redesignEnabled != useRedesign else { return } + shared.redesignEnabled = useRedesign + WidgetCenter.shared.reloadAllTimelines() + // The Live Activity otherwise keeps its old look until Loop next runs. + NotificationCenter.default.post(name: .LiveActivitySettingsChanged, object: nil) + } +} + +/// The redesign's root. The Now tab is Loop's own RootNavigationController, so every existing flow +/// (bolus, carbs, presets, alerts, device settings, deeplinks) keeps working from StatusTableViewController. +final class MainTabBarController: UITabBarController, UITabBarControllerDelegate { + + let rootNavigationController: RootNavigationController + private let provider: LoopHistoryProvider + private let settingsPlaceholder = UIViewController() + + init(rootNavigationController: RootNavigationController, deviceManager: DeviceDataManager) { + self.rootNavigationController = rootNavigationController + self.provider = LoopHistoryProvider(deviceManager: deviceManager) + super.init(nibName: nil, bundle: nil) + + rootNavigationController.tabBarItem = UITabBarItem(title: NSLocalizedString("Now", comment: "Title of the Now tab in the redesigned interface, showing current glucose and Loop status"), image: UIImage(systemName: "drop.fill"), tag: 0) + + let trends = UIHostingController(rootView: TrendsView(provider: provider)) + trends.tabBarItem = UITabBarItem(title: NSLocalizedString("Trends", comment: "Title of the Trends tab in the redesigned interface"), image: UIImage(systemName: "chart.bar.fill"), tag: 1) + + let logbook = UIHostingController(rootView: LogbookView(provider: provider, deviceManager: deviceManager)) + logbook.tabBarItem = UITabBarItem(title: NSLocalizedString("Logbook", comment: "Title of the Logbook tab in the redesigned interface, listing past events"), image: UIImage(systemName: "list.bullet"), tag: 2) + + settingsPlaceholder.tabBarItem = UITabBarItem(title: NSLocalizedString("Settings", comment: "Title of the Settings tab in the redesigned interface"), image: UIImage(systemName: "gearshape.fill"), tag: 3) + + viewControllers = [rootNavigationController, trends, logbook, settingsPlaceholder] + delegate = self + tabBar.tintColor = UIColor(named: "accent") + if #available(iOS 18.0, *) { + mode = .tabBar + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + /// Settings stays a sheet, as in classic Loop, so the tab only presents it. + func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { + guard viewController === settingsPlaceholder else { return true } + rootNavigationController.statusTableViewController?.presentSettingsFromTab() + return false + } + + func showNow() { + selectedViewController = rootNavigationController + } + + override func restoreUserActivityState(_ activity: NSUserActivity) { + showNow() + rootNavigationController.restoreUserActivityState(activity) + } +} + +extension UIViewController { + /// Loop's RootNavigationController, whether it is the window's root or the Now tab. + var loopRootNavigationController: RootNavigationController? { + if let root = self as? RootNavigationController { return root } + if let tabs = self as? MainTabBarController { return tabs.rootNavigationController } + return nil + } +} diff --git a/Loop/Redesign/NowScreen.swift b/Loop/Redesign/NowScreen.swift new file mode 100644 index 0000000000..fe9a3fd2ab --- /dev/null +++ b/Loop/Redesign/NowScreen.swift @@ -0,0 +1,853 @@ +// +// NowScreen.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import HealthKit +import LoopKit +import LoopKitUI +import LoopCore + +private typealias P = LoopDesign.Palette + +/// What the Now screen shows. StatusTableViewController owns it and asks it to refresh whenever Loop's data changes. +@MainActor +final class NowModel: ObservableObject { + + struct Reading: Equatable { + let mgdl: Double + let date: Date + let trend: GlucoseTrend? + /// Change since the previous reading, per 5 minutes. + let delta: Double? + } + + struct Device: Equatable { + let name: String + let message: String? + let state: DeviceStatusHighlightState? + /// Set when the message is the device's own status highlight, which the Now screen spells out in a notice. + var symbol: String? = nil + /// The device's lifecycle (pod, sensor) is near its end; the pill says so. + var endingSoon = false + } + + enum LoopState: Equatable { + case fresh + case stale + case failed + case never + } + + @Published private(set) var reading: Reading? + @Published private(set) var lastLoopCompleted: Date? + @Published private(set) var lastLoopFailed = false + @Published private(set) var closedLoop = false + /// Closed loop is switched on but Loop has paused it, for example while the CGM has no session or data. + @Published private(set) var closedLoopPaused = false + @Published private(set) var iob: Double? + @Published private(set) var cob: Double? + @Published private(set) var basalDeliveryState: PumpManagerStatus.BasalDeliveryState? + @Published private(set) var scheduledBasalRate: Double? + @Published private(set) var suspended = false + @Published private(set) var targetRange: ClosedRange? + @Published private(set) var predictionTargets: [TargetBand] = [] + @Published private(set) var todayTargets: [TargetBand] = [] + @Published private(set) var prediction: [GlucosePoint] = [] + @Published private(set) var recentGlucose: [GlucosePoint] = [] + @Published private(set) var historyError: String? + @Published private(set) var glucoseHistoryError: String? + @Published private(set) var today: DayHistory + @Published private(set) var pump: Device? + @Published private(set) var cgm: Device? + @Published private(set) var preMealAvailable = false + @Published private(set) var dosingAvailable = true + @Published private(set) var preMealOn = false + @Published private(set) var overrideName: String? + @Published private(set) var unit: GlucoseUnitStyle + @Published var now = Date() + /// Set by StatusTableViewController, which owns the onboarding state. + var isOnboardingComplete: () -> Bool = { true } + + let provider: LoopHistoryProvider + private let deviceManager: DeviceDataManager + private let automaticDosingStatus: AutomaticDosingStatus + private var refreshTask: Task? + private var pendingRefresh = false + + init(deviceManager: DeviceDataManager, automaticDosingStatus: AutomaticDosingStatus) { + self.deviceManager = deviceManager + self.automaticDosingStatus = automaticDosingStatus + self.provider = LoopHistoryProvider(deviceManager: deviceManager) + self.unit = provider.unitStyle + let start = Calendar.current.startOfDay(for: Date()) + self.today = DayHistory(window: DateInterval(start: start, duration: 86400)) + } + + var basalRate: Double? { + switch basalDeliveryState { + case .tempBasal(let dose)?: + return dose.startDate <= now && now < dose.endDate ? dose.unitsPerHour : scheduledBasalRate + case .active?: return scheduledBasalRate + case .suspended?, .suspending?: return 0 + default: return nil + } + } + + var loopState: LoopState { + guard let lastLoopCompleted else { return .never } + let age = now.timeIntervalSince(lastLoopCompleted) + if age <= 5 * 60 + 30 { return .fresh } + if age <= 15 * 60 { return .stale } + return .failed + } + + var readingIsStale: Bool { + guard let reading else { return true } + return now.timeIntervalSince(reading.date) > LoopCoreConstants.inputDataRecencyInterval + } + + /// Refreshes everything; calls made while a refresh runs are coalesced into one more. + func refresh() { + guard refreshTask == nil else { + pendingRefresh = true + return + } + refreshTask = Task { [weak self] in + await self?.load() + guard let self else { return } + self.refreshTask = nil + if self.pendingRefresh { + self.pendingRefresh = false + self.refresh() + } + } + } + + private func load() async { + let now = Date() + self.now = now + unit = provider.unitStyle + + let loopManager = deviceManager.loopManager! + let state: (predicted: [GlucosePoint], iob: Double?, cob: Double?, failed: Bool) = await withCheckedContinuation { continuation in + loopManager.getLoopState { _, state in + let predicted = (state.predictedGlucoseIncludingPendingInsulin ?? []).map { + GlucosePoint(date: $0.startDate, mgdl: $0.quantity.doubleValue(for: .milligramsPerDeciliter)) + } + continuation.resume(returning: (predicted, state.insulinOnBoard?.value, state.carbsOnBoard?.quantity.doubleValue(for: .gram()), state.error != nil)) + } + } + + let start = Calendar.current.startOfDay(for: now) + let window = DateInterval(start: start, end: Calendar.current.date(byAdding: .day, value: 1, to: start)!) + async let dayFetch = provider.dayHistory(window) + async let recentFetch = provider.glucose(DateInterval(start: now.addingTimeInterval(-3 * 3600), end: now)) + do { + today = try await dayFetch + historyError = nil + } catch { + historyError = error.localizedDescription + } + do { + recentGlucose = try await recentFetch + glucoseHistoryError = nil + } catch { + recentGlucose = [] + glucoseHistoryError = error.localizedDescription + } + + prediction = state.predicted + iob = state.iob + cob = state.cob + lastLoopFailed = state.failed + lastLoopCompleted = loopManager.lastLoopCompleted + closedLoop = automaticDosingStatus.automaticDosingEnabled + closedLoopPaused = loopManager.dosingEnabled && !automaticDosingStatus.isAutomaticDosingAllowed + targetRange = provider.glucoseTargetRange + predictionTargets = provider.glucoseTargetBands(in: DateInterval(start: now.addingTimeInterval(-3 * 3600), end: now.addingTimeInterval(3 * 3600))) + todayTargets = provider.glucoseTargetBands(in: window) + + if let latest = deviceManager.glucoseStore.latestGlucose { + let mgdl = latest.quantity.doubleValue(for: .milligramsPerDeciliter) + let previous = recentGlucose.last { $0.date < latest.startDate.addingTimeInterval(-60) } + var delta: Double? = nil + if let previous, latest.startDate.timeIntervalSince(previous.date) <= 15 * 60 { + delta = (mgdl - previous.mgdl) / latest.startDate.timeIntervalSince(previous.date) * 300 + } + // The CGM's own trend, as the classic HUD shows it. + reading = Reading(mgdl: mgdl, date: latest.startDate, trend: deviceManager.glucoseDisplay(for: latest)?.trendType, delta: delta) + } else { + reading = nil + } + + let scheduled = loopManager.basalRateScheduleApplyingOverrideHistory?.value(at: now) + scheduledBasalRate = scheduled + basalDeliveryState = loopManager.basalDeliveryState + switch basalDeliveryState { + case .suspended?, .suspending?: suspended = true + default: suspended = false + } + + pump = deviceManager.pumpManager.map { manager in + device(name: manager.localizedTitle, highlight: deviceManager.pumpStatusHighlight, progress: deviceManager.pumpLifecycleProgress) + } + cgm = deviceManager.cgmManager.map { manager in + device(name: manager.localizedTitle, highlight: deviceManager.cgmStatusHighlight, progress: deviceManager.cgmLifecycleProgress) + } + + let settings = loopManager.settings + // The same rules as the classic toolbar. + preMealAvailable = isOnboardingComplete() + && (automaticDosingStatus.automaticDosingEnabled || !FeatureFlags.simpleBolusCalculatorEnabled) + && settings.preMealTargetRange != nil + dosingAvailable = isOnboardingComplete() || deviceManager.pumpManager?.isOnboarded == true + preMealOn = settings.preMealTargetEnabled() + if let override = settings.scheduleOverride, override.isActive() { + switch override.context { + case .preset(let preset): overrideName = preset.name + case .custom: overrideName = NSLocalizedString("Custom preset", comment: "Name shown on the Now screen's Presets button when a custom (unnamed) override preset is active") + case .legacyWorkout: overrideName = NSLocalizedString("Workout", comment: "Name shown on the Now screen's Presets button when the legacy workout override is active") + case .preMeal: overrideName = nil + } + } else { + overrideName = nil + } + } + + private func device(name: String, highlight: DeviceStatusHighlight?, progress: DeviceLifecycleProgress?) -> Device { + if let highlight { + // Plugins wrap highlights onto two lines for the classic HUD ("Signal\nLoss"). + let message = highlight.localizedMessage.replacingOccurrences(of: "\n", with: " ") + return Device(name: name, message: message, state: highlight.state, symbol: highlight.imageName) + } + if let progress, progress.progressState == .warning || progress.progressState == .critical { + return Device(name: name, message: nil, state: progress.progressState == .critical ? .critical : .warning, endingSoon: true) + } + return Device(name: name, message: nil, state: nil) + } +} + +/// The buttons on the Now screen, wired to StatusTableViewController's existing flows. +struct NowActions { + var addCarbs: () -> Void = {} + var bolus: () -> Void = {} + var togglePreMeal: () -> Void = {} + var customPresets: () -> Void = {} + var showPrediction: () -> Void = {} + var showToday: () -> Void = {} + var showInsulin: () -> Void = {} + var showCarbs: () -> Void = {} + var pumpTapped: () -> Void = {} + var cgmTapped: () -> Void = {} + var loopStatusTapped: () -> Void = {} +} + +// MARK: - Header: title, status, hero, actions + +struct NowHeaderView: View { + @ObservedObject var model: NowModel + let actions: NowActions + + var body: some View { + VStack(alignment: .leading, spacing: LoopDesign.Space.s3) { + Text(NSLocalizedString("Now", comment: "Title at the top of the Now screen, showing current glucose and Loop status")) + .font(LoopDesign.Typeface.title) + .foregroundStyle(P.ink) + .accessibilityAddTraits(.isHeader) + statusRow + if !noticeItems.isEmpty { + notices + } + hero + actionRow + } + .padding(.horizontal, LoopDesign.Space.s4) + .padding(.top, LoopDesign.Space.s2) + .padding(.bottom, LoopDesign.Space.s2) + .frame(maxWidth: .infinity, alignment: .leading) + .background(P.surface) + .onReceive(Timer.publish(every: 30, on: .main, in: .common).autoconnect()) { model.now = $0 } + } + + // Status pills replace Loop's HUD icons with words. They wrap rather than scroll, so a device is never off-screen. + private var statusRow: some View { + FlowRow(spacing: LoopDesign.Space.s2) { + Button(action: actions.loopStatusTapped) { + StatusPill(text: loopText, dot: loopColor) + } + .accessibilityHint(NSLocalizedString("Shows when Loop last ran", comment: "VoiceOver hint for the Loop status pill and the Loop notice on the Now screen")) + Button(action: actions.pumpTapped) { + if let pump = model.pump { + StatusPill(text: pillText(pump), dot: pillColor(pump)) + } else { + StatusPill(text: NSLocalizedString("Add pump", comment: "Status pill on the Now screen when no pump is set up; tapping it starts pump setup"), dot: P.statusCritical) + } + } + .accessibilityHint(model.pump == nil + ? NSLocalizedString("Sets up a pump", comment: "VoiceOver hint for the Add pump status pill on the Now screen") + : NSLocalizedString("Opens pump settings", comment: "VoiceOver hint for the pump status pill and pump notice on the Now screen")) + Button(action: actions.cgmTapped) { + if let cgm = model.cgm { + StatusPill(text: pillText(cgm), dot: pillColor(cgm)) + } else { + StatusPill(text: NSLocalizedString("Add CGM", comment: "Status pill on the Now screen when no CGM is set up; tapping it starts CGM setup"), dot: P.statusCritical) + } + } + .accessibilityHint(model.cgm == nil + ? NSLocalizedString("Sets up a CGM", comment: "VoiceOver hint for the Add CGM status pill on the Now screen") + : NSLocalizedString("Opens CGM settings", comment: "VoiceOver hint for the CGM status pill and CGM notice on the Now screen")) + } + .buttonStyle(.plain) + } + + // A device problem or a stalled loop gets a notice in words under the pills, most serious first. + private var notices: some View { + let items = noticeItems + return VStack(spacing: LoopDesign.Space.s2) { + ForEach(items) { item in + Button(action: item.action) { + DeviceNotice(item: item) + } + .buttonStyle(.plain) + .accessibilityHint(item.hint) + } + } + } + + private var noticeItems: [DeviceNotice.Item] { + var items: [DeviceNotice.Item] = [] + if model.loopState == .failed, let last = model.lastLoopCompleted { + items.append(DeviceNotice.Item( + id: "loop", + severity: .critical, + symbol: "exclamationmark.arrow.circlepath", + title: String(format: NSLocalizedString("Loop hasn't run for %1$@", comment: "Notice title on the Now screen when Loop hasn't completed recently. (1: duration since Loop last ran, e.g. 16m)"), LoopFormat.ago(last, now: model.now)), + detail: NSLocalizedString("Insulin isn't being adjusted. Tap for details.", comment: "Notice detail on the Now screen when Loop hasn't completed recently"), + hint: NSLocalizedString("Shows when Loop last ran", comment: "VoiceOver hint for the Loop status pill and the Loop notice on the Now screen"), + action: actions.loopStatusTapped)) + } + // While suspended, Loop's own status row says so and offers Resume, so only a critical pump problem adds a notice. + if let pump = model.pump, let symbol = pump.symbol, let message = pump.message, + !model.suspended || pump.state == .critical { + let severity = DeviceNotice.Severity(pump.state) + items.append(DeviceNotice.Item( + id: "pump", + severity: severity, + symbol: symbol, + title: message, + detail: severity == .critical ? NSLocalizedString("Loop may not be giving insulin.", comment: "Notice detail on the Now screen under a critical pump problem reported by the pump") : nil, + hint: NSLocalizedString("Opens pump settings", comment: "VoiceOver hint for the pump status pill and pump notice on the Now screen"), + action: actions.pumpTapped)) + } + if let cgm = model.cgm, let symbol = cgm.symbol, let message = cgm.message { + let severity = DeviceNotice.Severity(cgm.state) + items.append(DeviceNotice.Item( + id: "cgm", + severity: severity, + symbol: symbol, + title: message, + detail: model.readingIsStale ? NSLocalizedString("Loop can't adjust insulin without readings.", comment: "Notice detail on the Now screen under a CGM problem when there is no recent glucose reading") : nil, + hint: NSLocalizedString("Opens CGM settings", comment: "VoiceOver hint for the CGM status pill and CGM notice on the Now screen"), + action: actions.cgmTapped)) + } + return items.sorted { $0.severity > $1.severity } + } + + private var loopText: String { + guard let last = model.lastLoopCompleted else { + if model.closedLoop { + return NSLocalizedString("Closed loop · not run yet", comment: "Status pill on the Now screen: closed loop is on but Loop has never completed") + } else if model.closedLoopPaused { + return NSLocalizedString("Closed loop paused · not run yet", comment: "Status pill on the Now screen: closed loop is switched on but paused (e.g. no CGM data), and Loop has never completed") + } else { + return NSLocalizedString("Open loop · not run yet", comment: "Status pill on the Now screen: closed loop is off and Loop has never completed") + } + } + let ago = LoopFormat.ago(last, now: model.now) + if model.loopState == .failed { + return String(format: NSLocalizedString("Loop failed · %1$@", comment: "Status pill on the Now screen: Loop hasn't completed for over 15 minutes. (1: duration since Loop last ran, e.g. 16m)"), ago) + } else if model.closedLoop { + return String(format: NSLocalizedString("Closed loop · %1$@", comment: "Status pill on the Now screen: closed loop is on and Loop last ran this long ago. (1: duration, e.g. 3m)"), ago) + } else if model.closedLoopPaused { + return String(format: NSLocalizedString("Closed loop paused · %1$@", comment: "Status pill on the Now screen: closed loop is switched on but paused (e.g. no CGM data), and Loop last ran this long ago. (1: duration, e.g. 3m)"), ago) + } else { + return String(format: NSLocalizedString("Open loop · %1$@", comment: "Status pill on the Now screen: closed loop is off (Loop recommends only) and Loop last ran this long ago. (1: duration, e.g. 3m)"), ago) + } + } + + /// Green only while closed loop is running; open loop that ran on time is neutral. + private var loopColor: Color { + switch model.loopState { + case .fresh: return model.closedLoop ? P.statusAutomated : model.closedLoopPaused ? P.statusWarning : P.inkMuted + case .stale: return P.statusWarning + case .failed, .never: return P.statusCritical + } + } + + /// A highlight (always a plugin message with a symbol) is spelled out in its notice, so its pill keeps to the device name. + private func pillText(_ device: NowModel.Device) -> String { + guard device.symbol == nil else { return device.name } + if device.endingSoon { + return String(format: NSLocalizedString("%1$@ · ending soon", comment: "Status pill on the Now screen when a pump pod or CGM sensor is near the end of its life. (1: device name from the pump or CGM plugin, e.g. Omnipod 5)"), device.name) + } + return device.name + } + + private func pillColor(_ device: NowModel.Device) -> Color? { + switch device.state { + case .critical?: return P.statusCritical + case .warning?: return P.statusWarning + default: return device.symbol == nil ? nil : P.inkMuted + } + } + + private var hero: some View { + LoopCard { + HStack(alignment: .top) { + VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .center, spacing: LoopDesign.Space.s2) { + if let reading = model.reading, !model.readingIsStale { + Text(model.unit.format(reading.mgdl)) + .font(LoopDesign.Typeface.glucoseHero) + .foregroundStyle(P.ink) + .lineLimit(1) + .minimumScaleFactor(0.6) + if let trend = reading.trend { + Image(systemName: Self.symbol(for: trend)) + .font(.system(size: 30, weight: .bold)) + .foregroundStyle(P.glucose) + .accessibilityLabel(trend.localizedDescription) + } + } else { + Text(NSLocalizedString("No reading", comment: "Shown on the Now screen in place of the glucose value when there is no recent CGM reading")) + .font(.system(size: 34, weight: .bold, design: .rounded)) + .foregroundStyle(P.inkMuted) + } + } + Text(readingDetail) + .font(LoopDesign.Typeface.subhead) + .foregroundStyle(P.inkMuted) + if let rangePill { + StatusPill(text: rangePill.0, dot: rangePill.1) + .padding(.top, LoopDesign.Space.s1) + } + } + Spacer(minLength: LoopDesign.Space.s2) + VStack(alignment: .trailing, spacing: 2) { + if let reading = model.reading { + Text(LoopFormat.time(reading.date)) + } + if let target = model.targetRange { + Text(String(format: NSLocalizedString("Target %1$@–%2$@", comment: "Glucose target range on the Now screen hero card. (1: lower bound; 2: upper bound)"), model.unit.format(target.lowerBound), model.unit.format(target.upperBound))) + } + } + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + .padding(.top, LoopDesign.Space.s4) + } + .accessibilityElement(children: .combine) + + AdaptiveRow { + // As on the classic charts: insulin opens Loop's delivery history, carbs its absorption screen. + Button(action: actions.showInsulin) { + ValueTile(label: NSLocalizedString("IOB", comment: "Abbreviation for insulin on board; label of a tile on the Now screen")) { + Text(model.iob.map(LoopFormat.doseUnits) ?? "–") + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.insulinInk) + } + } + .buttonStyle(.plain) + .accessibilityHint(NSLocalizedString("Opens insulin delivery history", comment: "VoiceOver hint for the IOB tile on the Now screen")) + Button(action: actions.showCarbs) { + ValueTile(label: NSLocalizedString("COB", comment: "Abbreviation for carbs on board; label of a tile on the Now screen")) { + Text(model.cob.map(LoopFormat.grams) ?? "–") + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.carbsInk) + } + } + .buttonStyle(.plain) + .accessibilityHint(NSLocalizedString("Opens carb absorption", comment: "VoiceOver hint for the COB tile on the Now screen")) + ValueTile(label: NSLocalizedString("Basal", comment: "Label of a tile showing the current basal rate (Now screen) or the day's basal insulin total (Today so far totals)")) { + VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .firstTextBaseline, spacing: 2) { + Text(model.basalRate.map { LoopFormat.number($0, decimals: 2) } ?? "–") + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.ink) + Text(NSLocalizedString("U/h", comment: "Abbreviation for insulin units per hour")) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + if model.suspended { + Text(NSLocalizedString("Suspended", comment: "Shown in the Basal tile on the Now screen when insulin delivery is suspended")) + .font(LoopDesign.Typeface.footnote.weight(.semibold)) + .foregroundStyle(P.criticalInk) + } else if let rate = model.basalRate, let scheduled = model.scheduledBasalRate { + Text(String(format: NSLocalizedString("%1$@ vs plan", comment: "Basal tile on the Now screen: how the current basal rate differs from the scheduled rate. (1: signed difference in U/h, e.g. +0.25)"), LoopFormat.signed(rate - scheduled))) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.insulinInk) + .lineLimit(1) + .minimumScaleFactor(0.8) + } + } + } + } + .fixedSize(horizontal: false, vertical: true) + } + .opacity(model.readingIsStale && model.reading != nil ? 0.7 : 1) + } + + private var readingDetail: String { + guard let reading = model.reading else { return model.unit.unitName } + if model.readingIsStale { + return String(format: NSLocalizedString("Last reading %1$@ ago", comment: "Shown on the Now screen under No reading when the latest CGM reading is too old. (1: duration, e.g. 25m)"), LoopFormat.ago(reading.date, now: model.now)) + } + guard let delta = reading.delta else { return model.unit.unitName } + let change = model.unit.isMmol ? LoopFormat.signed(delta / GlucoseUnitStyle.mgdlPerMmol, decimals: 1) : LoopFormat.signed(delta, decimals: 0) + return String(format: NSLocalizedString("%1$@ · %2$@ in 5 min", comment: "Under the glucose value on the Now screen: the glucose unit and how much glucose changed over 5 minutes. (1: glucose unit, e.g. mmol/L; 2: signed change, e.g. +0.3)"), model.unit.unitName, change) + } + + /// Low and high get a pill with words; the number itself is never tinted. + private var rangePill: (String, Color)? { + guard let reading = model.reading, !model.readingIsStale else { return nil } + if reading.mgdl < 54 { return (NSLocalizedString("Urgent low", comment: "Pill under the glucose value on the Now screen when glucose is below 54 mg/dL (3.0 mmol/L)"), P.statusCritical) } + if reading.mgdl < 70 { return (NSLocalizedString("Low", comment: "Pill under the glucose value on the Now screen when glucose is below 70 mg/dL (3.9 mmol/L)"), P.statusCritical) } + if reading.mgdl > 250 { return (NSLocalizedString("High", comment: "Pill under the glucose value on the Now screen when glucose is above 250 mg/dL (13.9 mmol/L)"), P.statusWarning) } + return nil + } + + static func symbol(for trend: GlucoseTrend) -> String { + switch trend { + case .upUpUp: return "arrow.up.to.line" + case .upUp: return "chevron.up.2" + case .up: return "arrow.up" + case .flat: return "arrow.right" + case .down: return "arrow.down" + case .downDown: return "chevron.down.2" + case .downDownDown: return "arrow.down.to.line" + } + } + + private var actionRow: some View { + AdaptiveRow { + actionButton(NSLocalizedString("Add carbs", comment: "Button on the Now screen that opens carb entry"), systemImage: "fork.knife", fill: P.carbs, text: P.onFill, action: actions.addCarbs) + .disabled(!model.dosingAvailable) + .opacity(model.dosingAvailable ? 1 : 0.4) + actionButton(NSLocalizedString("Bolus", comment: "Button on the Now screen that opens the bolus screen"), systemImage: "syringe.fill", fill: P.insulin, text: P.onFill, action: actions.bolus) + .disabled(!model.dosingAvailable) + .opacity(model.dosingAvailable ? 1 : 0.4) + if model.preMealAvailable { + presetsMenu + } else { + // Only one choice, so open it directly, as the classic Workout button does. + Button(action: actions.customPresets) { + actionLabel(presetsTitle, systemImage: "slider.horizontal.3", fill: presetsFill, text: P.ink) + } + .buttonStyle(.plain) + .accessibilityLabel(NSLocalizedString("Presets", comment: "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item")) + .accessibilityValue(presetsActive ? presetsTitle : "") + } + } + .fixedSize(horizontal: false, vertical: true) + } + + private var presetsFill: Color { + model.preMealOn || model.overrideName != nil ? P.accent.opacity(0.18) : P.surfaceSunken + } + + private var presetsMenu: some View { + Menu { + if model.preMealAvailable { + Button(action: actions.togglePreMeal) { + Label(model.preMealOn + ? NSLocalizedString("Turn off pre-meal", comment: "Menu item under Presets on the Now screen that turns off the pre-meal target") + : NSLocalizedString("Pre-meal", comment: "Menu item under Presets on the Now screen that turns on the pre-meal target"), + systemImage: "fork.knife.circle") + } + } + Button(action: actions.customPresets) { + if let name = model.overrideName { + Label(String(format: NSLocalizedString("Turn off %1$@", comment: "Menu item under Presets on the Now screen that turns off the active override preset. (1: preset name)"), name), systemImage: "slider.horizontal.3") + } else { + Label(NSLocalizedString("Presets", comment: "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item"), systemImage: "slider.horizontal.3") + } + } + } label: { + actionLabel(presetsTitle, systemImage: "slider.horizontal.3", fill: presetsFill, text: P.ink) + } + .accessibilityLabel(NSLocalizedString("Presets", comment: "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item")) + .accessibilityValue(presetsActive ? presetsTitle : "") + } + + private var presetsActive: Bool { + model.preMealOn || model.overrideName != nil + } + + private var presetsTitle: String { + if model.preMealOn { return NSLocalizedString("Pre-meal on", comment: "Presets button title on the Now screen while the pre-meal target is on") } + if let name = model.overrideName { return name } + return NSLocalizedString("Presets", comment: "Button on the Now screen that opens override presets (and pre-meal); also its VoiceOver label and menu item") + } + + private func actionButton(_ title: String, systemImage: String, fill: Color, text: Color, action: @escaping () -> Void) -> some View { + Button(action: action) { + actionLabel(title, systemImage: systemImage, fill: fill, text: text) + } + .buttonStyle(.plain) + } + + private func actionLabel(_ title: String, systemImage: String, fill: Color, text: Color) -> some View { + // Longer languages ("Agregar carbohidratos") wrap onto a second line rather than truncate. + Text(title) + .font(LoopDesign.Typeface.subhead.weight(.semibold)) + .lineLimit(2) + .multilineTextAlignment(.center) + .minimumScaleFactor(0.8) + .allowsTightening(true) + .foregroundStyle(text) + .padding(.horizontal, LoopDesign.Space.s1) + .padding(.vertical, LoopDesign.Space.s1) + .frame(maxWidth: .infinity, minHeight: 44, maxHeight: .infinity) + .background(fill, in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md, style: .continuous)) + .contentShape(RoundedRectangle(cornerRadius: LoopDesign.Radius.md)) + } +} + +// MARK: - Charts: next 3 hours and today so far + +struct NowChartsView: View { + @ObservedObject var model: NowModel + let actions: NowActions + + var body: some View { + VStack(spacing: LoopDesign.Space.s4) { + predictionCard + todayCard + } + .padding(.horizontal, LoopDesign.Space.s4) + .padding(.top, LoopDesign.Space.s2) + .padding(.bottom, LoopDesign.Space.s6) + .frame(maxWidth: .infinity) + .background(P.surface) + } + + private var readings: [GlucosePoint] { + model.recentGlucose.filter { $0.date >= model.now.addingTimeInterval(-3 * 3600) } + } + + private var predictionCard: some View { + Button(action: actions.showPrediction) { + LoopCard { + CardHeader(title: NSLocalizedString("Next 3 hours", comment: "Title of the prediction chart card on the Now screen")) { + // Loop's eventual glucose is the end of its prediction, which can run past the three hours drawn. + if let last = model.prediction.last { + Text(String(format: NSLocalizedString("Eventually %1$@ %2$@", comment: "Prediction card on the Now screen: Loop's eventual predicted glucose. (1: glucose value; 2: glucose unit, e.g. mmol/L)"), model.unit.format(last.mgdl), model.unit.unitName)) + } + } + if readings.isEmpty && model.prediction.isEmpty { + ChartPlaceholder(message: model.glucoseHistoryError == nil + ? NSLocalizedString("No CGM data in the last 3 hours", comment: "Empty prediction chart on the Now screen") + : NSLocalizedString("Couldn't load recent CGM readings", comment: "Prediction chart on the Now screen when recent glucose couldn't be read")) + } else { + PredictionChartView(readings: readings, prediction: model.prediction, unit: model.unit, + targetBands: model.predictionTargets, now: model.now) + } + ChartLegend(items: [ + LegendItem(swatch: .dot(P.glucose), label: NSLocalizedString("Readings", comment: "Chart legend on the Now screen: dots are CGM glucose readings")), + LegendItem(swatch: .dash(P.glucose), label: NSLocalizedString("Loop prediction", comment: "Chart legend on the Now screen: dashed line is Loop's predicted glucose")), + ]) + if let error = model.glucoseHistoryError { + Text(String(format: NSLocalizedString("Recent readings unavailable: %1$@", comment: "Error under the prediction chart on the Now screen. (1: system error description)"), error)) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.criticalInk) + } + } + } + .buttonStyle(.plain) + .accessibilityHint(NSLocalizedString("Opens Loop's prediction breakdown", comment: "VoiceOver hint for the prediction card on the Now screen")) + } + + private var todayCard: some View { + Button(action: actions.showToday) { + LoopCard { + CardHeader(title: NSLocalizedString("Today so far", comment: "Title of the card on the Now screen showing today's insulin and carbs")) { + if model.historyError == nil { + HStack(spacing: 4) { + Text(LoopFormat.totalUnits(model.today.totalUnits)).foregroundStyle(P.insulinInk) + Text(verbatim: "·") + Text(LoopFormat.grams(model.today.carbGrams)).foregroundStyle(P.carbsInk) + } + } + } + if let error = model.historyError { + ChartPlaceholder(message: String(format: NSLocalizedString("Couldn't load today's history: %1$@", comment: "Shown on the Now screen's Today so far card when history couldn't be read. (1: system error description)"), error)) + } else { + InsulinTimelineView(history: model.today, unit: model.unit, targetBands: model.todayTargets, now: model.now, height: 230) + DayTotalsTiles(history: model.today) + ChartLegend(items: DayTotalsTiles.legend) + } + } + } + .buttonStyle(.plain) + .accessibilityHint(NSLocalizedString("Opens the full day", comment: "VoiceOver hint for the Today so far card on the Now screen")) + } +} + +/// Bolus, basal and carb totals under a timeline. +struct DayTotalsTiles: View { + let history: DayHistory + + static let legend: [LegendItem] = [ + LegendItem(swatch: .solid(P.insulin), label: NSLocalizedString("Bolus", comment: "Chart legend: solid bars are manual boluses")), + LegendItem(swatch: .outline(P.insulin), label: NSLocalizedString("Automatic", comment: "Chart legend: outlined bars are automatic boluses given by Loop")), + LegendItem(swatch: .basal, label: NSLocalizedString("Basal given", comment: "Chart legend: filled area is basal insulin actually delivered")), + LegendItem(swatch: .dash(P.basalScheduled), label: NSLocalizedString("Scheduled", comment: "Chart legend: dashed line is the scheduled basal rate")), + ] + + var body: some View { + AdaptiveRow { + ValueTile(label: NSLocalizedString("Bolus", comment: "Label of a tile showing the day's total bolus insulin")) { + Text(LoopFormat.totalUnits(history.bolusUnits)) + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.insulinInk) + } + ValueTile(label: NSLocalizedString("Basal", comment: "Label of a tile showing the current basal rate (Now screen) or the day's basal insulin total (Today so far totals)")) { + Text(LoopFormat.totalUnits(history.basalUnits)) + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.insulinInk) + } + ValueTile(label: NSLocalizedString("Carbs", comment: "Label of a tile showing the day's total carbohydrate")) { + Text(LoopFormat.grams(history.carbGrams)) + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.carbsInk) + } + } + .fixedSize(horizontal: false, vertical: true) + } +} + +// MARK: - Notices + +/// One problem in words: what the device or Loop reports, what it means, and where to go. +struct DeviceNotice: View { + enum Severity: Int, Comparable { + case info, warning, critical + + init(_ state: DeviceStatusHighlightState?) { + switch state { + case .critical?: self = .critical + case .warning?: self = .warning + default: self = .info + } + } + + static func < (lhs: Severity, rhs: Severity) -> Bool { lhs.rawValue < rhs.rawValue } + } + + struct Item: Identifiable { + let id: String + let severity: Severity + let symbol: String + let title: String + let detail: String? + let hint: String + let action: () -> Void + } + + let item: Item + + private var tint: Color { + switch item.severity { + case .critical: return P.statusCritical + case .warning: return P.statusWarning + case .info: return P.inkMuted + } + } + + var body: some View { + HStack(alignment: .center, spacing: LoopDesign.Space.s3) { + Image(systemName: item.symbol) + .font(.system(size: 20, weight: .semibold)) + .foregroundStyle(item.severity == .critical ? P.criticalInk : tint) + .frame(width: 24) + .accessibilityHidden(true) + VStack(alignment: .leading, spacing: 2) { + Text(item.title) + .font(LoopDesign.Typeface.headline) + .foregroundStyle(item.severity == .critical ? P.criticalInk : P.ink) + if let detail = item.detail { + Text(detail) + .font(LoopDesign.Typeface.subhead) + .foregroundStyle(P.ink) + .fixedSize(horizontal: false, vertical: true) + } + } + Spacer(minLength: 0) + Image(systemName: "chevron.right") + .font(.footnote.weight(.semibold)) + .foregroundStyle(P.inkMuted) + .accessibilityHidden(true) + } + .padding(LoopDesign.Space.s3) + .frame(maxWidth: .infinity, alignment: .leading) + .background(tint.opacity(item.severity == .info ? 0.12 : 0.16), in: RoundedRectangle(cornerRadius: LoopDesign.Radius.lg, style: .continuous)) + .overlay( + RoundedRectangle(cornerRadius: LoopDesign.Radius.lg, style: .continuous) + .strokeBorder(tint.opacity(item.severity == .info ? 0 : 0.45), lineWidth: 1) + ) + .contentShape(Rectangle()) + .accessibilityElement(children: .combine) + } +} + +/// Lays its children out left to right and starts a new line when the next one won't fit. +struct FlowRow: Layout { + var spacing: CGFloat = 8 + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + let rows = arrange(width: proposal.width ?? .infinity, subviews: subviews) + let width = rows.map { $0.width }.max() ?? 0 + let height = rows.map { $0.height }.reduce(0, +) + spacing * CGFloat(max(rows.count - 1, 0)) + return CGSize(width: proposal.width ?? width, height: height) + } + + func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { + var y = bounds.minY + for row in arrange(width: bounds.width, subviews: subviews) { + var x = bounds.minX + for index in row.indices { + let size = subviews[index].sizeThatFits(ProposedViewSize(width: bounds.width, height: nil)) + subviews[index].place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(width: min(size.width, bounds.width), height: size.height)) + x += min(size.width, bounds.width) + spacing + } + y += row.height + spacing + } + } + + private struct Row { + var indices: [Int] = [] + var width: CGFloat = 0 + var height: CGFloat = 0 + } + + private func arrange(width: CGFloat, subviews: Subviews) -> [Row] { + var rows: [Row] = [] + var row = Row() + for index in subviews.indices { + let size = subviews[index].sizeThatFits(ProposedViewSize(width: width, height: nil)) + let itemWidth = min(size.width, width) + if !row.indices.isEmpty && row.width + spacing + itemWidth > width { + rows.append(row) + row = Row() + } + row.width += (row.indices.isEmpty ? 0 : spacing) + itemWidth + row.height = max(row.height, size.height) + row.indices.append(index) + } + if !row.indices.isEmpty { rows.append(row) } + return rows + } +} diff --git a/Loop/Redesign/TrendsComponents.swift b/Loop/Redesign/TrendsComponents.swift new file mode 100644 index 0000000000..efd4cc2989 --- /dev/null +++ b/Loop/Redesign/TrendsComponents.swift @@ -0,0 +1,634 @@ +// +// TrendsComponents.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import Charts + +private typealias P = LoopDesign.Palette + +// MARK: - RangeSelector + +enum TrendsPeriod: Int, CaseIterable, Identifiable { + case day = 1 + case week = 7 + case twoWeeks = 14 + case month = 30 + case quarter = 90 + + var id: Int { rawValue } + + var label: String { + self == .day + ? NSLocalizedString("Day (Trends period)", value: "Day", comment: "Trends period picker: a period of one calendar day (not daytime)") + : String(format: NSLocalizedString("%1$@ d", comment: "Trends period picker, short label for a period of several days, e.g. 7 d. (1: number of days)"), + LoopFormat.number(Double(rawValue), decimals: 0)) + } + + var accessibilityName: String { + self == .day + ? NSLocalizedString("Day (Trends period)", value: "Day", comment: "Trends period picker: a period of one calendar day (not daytime)") + : String.localizedStringWithFormat(NSLocalizedString("%lld days", comment: "Trends period picker, VoiceOver name for a period of several days. (1: number of days)"), rawValue) + } + + /// The period ending on `endDay` (inclusive), cut off at `now` when it ends today. + func interval(endingOn endDay: Date, now: Date = Date(), calendar: Calendar = .current) -> DateInterval { + let endOfDay = calendar.date(byAdding: .day, value: 1, to: calendar.startOfDay(for: endDay))! + let start = calendar.date(byAdding: .day, value: -rawValue, to: endOfDay)! + return DateInterval(start: start, end: min(endOfDay, now)) + } +} + +struct RangeSelectorView: View { + @Binding var period: TrendsPeriod + @Binding var endDay: Date + var now: Date = Date() + + private var calendar: Calendar { .current } + + private var canStepForward: Bool { + !calendar.isDate(endDay, inSameDayAs: now) && endDay < now + } + + var body: some View { + VStack(spacing: LoopDesign.Space.s3) { + HStack(spacing: 2) { + ForEach(TrendsPeriod.allCases) { option in + Button { + withAnimation(.snappy(duration: 0.2)) { period = option } + } label: { + Text(option.label) + .font(.footnote.weight(.semibold)) + .foregroundStyle(P.ink) + .frame(maxWidth: .infinity, minHeight: 30) + .background { + if option == period { + Capsule().fill(P.controlThumb).shadow(color: .black.opacity(0.12), radius: 3, y: 1) + } + } + .contentShape(Capsule()) + } + .buttonStyle(.plain) + .accessibilityLabel(option.accessibilityName) + .accessibilityAddTraits(option == period ? .isSelected : []) + } + } + .padding(2) + .background(P.surfaceSunken, in: Capsule()) + + HStack { + stepButton(systemName: "chevron.left", label: NSLocalizedString("Previous period", comment: "VoiceOver label for the Trends button that moves back one period"), enabled: true) { step(-1) } + Spacer() + Text(LoopFormat.range(period.interval(endingOn: endDay, now: now).start, endDay)) + .font(LoopDesign.Typeface.headline.monospacedDigit()) + .foregroundStyle(P.ink) + Spacer() + stepButton(systemName: "chevron.right", label: NSLocalizedString("Next period", comment: "VoiceOver label for the Trends button that moves forward one period"), enabled: canStepForward) { step(1) } + } + } + } + + private func step(_ direction: Int) { + guard let next = calendar.date(byAdding: .day, value: direction * period.rawValue, to: endDay) else { return } + endDay = min(next, now) + } + + private func stepButton(systemName: String, label: String, enabled: Bool, action: @escaping () -> Void) -> some View { + Button(action: action) { + Image(systemName: systemName) + .font(.footnote.weight(.semibold)) + .frame(width: 30, height: 30) + .background(P.surfaceRaised, in: Circle()) + .overlay(Circle().strokeBorder(P.separator)) + } + .buttonStyle(.plain) + .foregroundStyle(enabled ? P.ink : P.inkMuted.opacity(0.5)) + .disabled(!enabled) + .accessibilityLabel(label) + } +} + +// MARK: - StatGrid + +struct StatTile: Identifiable { + let label: String + let value: String + let unit: String? + let detail: String? + var id: String { label } +} + +struct StatGridView: View { + @Environment(\.dynamicTypeSize) private var typeSize + let tiles: [StatTile] + + /// Pairs of tiles, so both tiles in a row take the taller one's height; one per row at accessibility sizes. + private var rows: [[StatTile]] { + let shown = Array(tiles.prefix(6)) + let perRow = typeSize.isAccessibilitySize ? 1 : 2 + return stride(from: 0, to: shown.count, by: perRow).map { Array(shown[$0.. some View { + VStack(alignment: .leading, spacing: 2) { + Text(tile.label) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + HStack(alignment: .firstTextBaseline, spacing: 2) { + Text(tile.value) + .font(LoopDesign.Typeface.statValue) + .foregroundStyle(P.ink) + .minimumScaleFactor(0.7) + .lineLimit(1) + if let unit = tile.unit { + Text(unit) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + } + if let detail = tile.detail { + Text(detail) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + .lineLimit(2) + } + } + .padding(LoopDesign.Space.s3) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background(P.surfaceSunken, in: RoundedRectangle(cornerRadius: LoopDesign.Radius.md, style: .continuous)) + .accessibilityElement(children: .combine) + } +} + +// MARK: - TimeInRange + +extension LoopHistoryMath.RangeBand { + /// The band's name in the user's language. + var localizedName: String { + switch self { + case .veryHigh: return NSLocalizedString("Very high", comment: "Time in range band: glucose above 250 mg/dL (13.9 mmol/L)") + case .high: return NSLocalizedString("High", comment: "Time in range band: glucose 181–250 mg/dL (10.1–13.9 mmol/L)") + case .inRange: return NSLocalizedString("In range", comment: "Time in range band: glucose 70–180 mg/dL (3.9–10.0 mmol/L)") + case .low: return NSLocalizedString("Low", comment: "Time in range band: glucose 54–69 mg/dL (3.0–3.8 mmol/L)") + case .veryLow: return NSLocalizedString("Very low", comment: "Time in range band: glucose below 54 mg/dL (3.0 mmol/L)") + } + } + + /// Consensus thresholds with the user's decimal separator, e.g. "3,9–10,0". + func localizedThresholds(_ unit: GlucoseUnitStyle) -> String { + let decimals = unit.isMmol ? 1 : 0 + let n: (Double) -> String = { LoopFormat.number($0, decimals: decimals) } + switch (self, unit.isMmol) { + case (.veryHigh, true): return "> " + n(13.9) + case (.high, true): return n(10.1) + "–" + n(13.9) + case (.inRange, true): return n(3.9) + "–" + n(10.0) + case (.low, true): return n(3.0) + "–" + n(3.8) + case (.veryLow, true): return "< " + n(3.0) + case (.veryHigh, false): return "> " + n(250) + case (.high, false): return n(181) + "–" + n(250) + case (.inRange, false): return n(70) + "–" + n(180) + case (.low, false): return n(54) + "–" + n(69) + case (.veryLow, false): return "< " + n(54) + } + } +} + +/// "12%" in the user's language. +private func percentText(_ value: Double, decimals: Int = 0) -> String { + String(format: NSLocalizedString("%1$@%%", comment: "A percentage. (1: number)"), LoopFormat.number(value, decimals: decimals)) +} + +struct TimeInRangeView: View { + @Environment(\.dynamicTypeSize) private var typeSize + + /// Fractions per band, 0–1. + let fractions: [LoopHistoryMath.RangeBand: Double] + let unit: GlucoseUnitStyle + + private var percentages: [LoopHistoryMath.RangeBand: Int] { LoopHistoryMath.roundedPercentages(fractions) } + + static func color(_ band: LoopHistoryMath.RangeBand) -> Color { + switch band { + case .veryHigh: return P.rangeVeryHigh + case .high: return P.rangeHigh + case .inRange: return P.rangeIn + case .low: return P.rangeLow + case .veryLow: return P.rangeVeryLow + } + } + + var body: some View { + HStack(alignment: .top, spacing: LoopDesign.Space.s4) { + bar + .frame(width: 14) + VStack(spacing: LoopDesign.Space.s2) { + ForEach(LoopHistoryMath.RangeBand.allCases) { band in + row(band) + } + } + } + .fixedSize(horizontal: false, vertical: true) + } + + private var bar: some View { + GeometryReader { geometry in + let minimum: CGFloat = 4 + let bands = LoopHistoryMath.RangeBand.allCases + let raw = bands.map { CGFloat(fractions[$0] ?? 0) } + let floors = raw.map { $0 > 0 ? max(minimum, $0 * geometry.size.height) : 0 } + let spare = geometry.size.height - floors.reduce(0, +) + // Trim the space the minimums borrowed from the largest band. + let largest = raw.indices.max { raw[$0] < raw[$1] } ?? 2 + VStack(spacing: 1) { + ForEach(Array(bands.enumerated()), id: \.offset) { index, band in + let height = index == largest ? max(0, floors[index] + spare) : floors[index] + if height > 0 { + Rectangle().fill(Self.color(band)).frame(height: max(0, height - 1)) + } + } + } + .clipShape(Capsule()) + } + .accessibilityHidden(true) + } + + private func row(_ band: LoopHistoryMath.RangeBand) -> some View { + let fraction = fractions[band] ?? 0 + let hours = fraction * 24 + let thresholds = Text(band.localizedThresholds(unit)) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + return VStack(alignment: .leading, spacing: 0) { + HStack(alignment: .firstTextBaseline, spacing: LoopDesign.Space.s2) { + Text(percentText(Double(percentages[band] ?? 0))) + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.ink) + .frame(minWidth: typeSize.isAccessibilitySize ? nil : 52, alignment: .trailing) + Text(band.localizedName) + .font(LoopDesign.Typeface.subhead) + .foregroundStyle(P.ink) + if !typeSize.isAccessibilitySize { + thresholds + } + Spacer(minLength: LoopDesign.Space.s1) + Text(String(format: NSLocalizedString("%1$@ h", comment: "Time in range row: average hours a day spent in the band, abbreviated. (1: hours with one decimal)"), + LoopFormat.number(hours, decimals: 1))) + .font(LoopDesign.Typeface.footnote.monospacedDigit()) + .foregroundStyle(P.inkMuted) + } + if typeSize.isAccessibilitySize { + thresholds + } + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(String(format: NSLocalizedString("%1$@, %2$@ %3$@: %4$@ percent, %5$@ hours a day", comment: "VoiceOver label for a Time in range row. (1: band name, e.g. In range, 2: glucose thresholds, e.g. 3.9–10.0, 3: glucose unit, 4: percentage number, 5: average hours a day with one decimal)"), + band.localizedName, band.localizedThresholds(unit), unit.unitName, + LoopFormat.number(Double(percentages[band] ?? 0), decimals: 0), LoopFormat.number(hours, decimals: 1))) + } +} + +// MARK: - AGP + +struct AGPChartView: View { + let slots: [LoopHistoryMath.AGPSlot] + let readings: [GlucosePoint] + let days: Int + let unit: GlucoseUnitStyle + let targetRange: ClosedRange? + var height: CGFloat = 180 + + private func v(_ mgdl: Double) -> Double { + min(max(unit.value(mgdl), unit.agpDomain.lowerBound), unit.agpDomain.upperBound) + } + + private static let hourTicks = [0, 360, 720, 1080, 1440] + + private static func label(minute: Int) -> String { + let minute = minute % 1440 + let date = Calendar.current.date(bySettingHour: minute / 60, minute: minute % 60, second: 0, of: Date())! + return DayAxis.hourLabel(date) + } + + var enoughDays: Bool { days >= 5 } + + var body: some View { + VStack(alignment: .leading, spacing: LoopDesign.Space.s2) { + if readings.isEmpty { + ChartPlaceholder(message: NSLocalizedString("No CGM data in this period", comment: "Trends chart placeholder when the period has no glucose readings"), height: height) + } else { + chart.frame(height: height) + if !enoughDays { + Text(String(format: NSLocalizedString("Not enough days for a pattern: %1$@ of 5", comment: "Trends Daily pattern footnote when fewer than 5 days have readings; the chart shows raw readings instead. (1: days with readings)"), + LoopFormat.number(Double(days), decimals: 0))) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + } + } + } + + private func minuteOfDay(_ date: Date) -> Int { + let parts = Calendar.current.dateComponents([.hour, .minute], from: date) + return (parts.hour ?? 0) * 60 + (parts.minute ?? 0) + } + + private var chart: some View { + Chart { + if let targetRange { + RectangleMark(xStart: .value("Start", 0), xEnd: .value("End", 1440), + yStart: .value("Low", v(targetRange.lowerBound)), yEnd: .value("High", v(targetRange.upperBound))) + .foregroundStyle(P.targetBand) + } + if enoughDays { + ForEach(slots, id: \.minute) { slot in + AreaMark(x: .value("Time", slot.minute), yStart: .value("5%", v(slot.p5)), yEnd: .value("95%", v(slot.p95)), series: .value("Band", "outer")) + .foregroundStyle(P.agpOuter) + .interpolationMethod(.monotone) + } + ForEach(slots, id: \.minute) { slot in + AreaMark(x: .value("Time", slot.minute), yStart: .value("25%", v(slot.p25)), yEnd: .value("75%", v(slot.p75)), series: .value("Band", "inner")) + .foregroundStyle(P.agpInner) + .interpolationMethod(.monotone) + } + ForEach(slots, id: \.minute) { slot in + LineMark(x: .value("Time", slot.minute), y: .value("Median", v(slot.p50)), series: .value("Band", "median")) + .foregroundStyle(P.glucose) + .lineStyle(StrokeStyle(lineWidth: 2.5)) + .interpolationMethod(.monotone) + } + } else { + ForEach(Array(readings.enumerated()), id: \.offset) { _, point in + PointMark(x: .value("Time", minuteOfDay(point.date)), y: .value("Glucose", v(point.mgdl))) + .symbolSize(8) + .foregroundStyle(P.glucose) + } + } + } + .chartXScale(domain: 0...1440) + .chartYScale(domain: unit.agpDomain) + .chartXAxis { + AxisMarks(values: Self.hourTicks) { value in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel { + if let minute = value.as(Int.self) { Text(Self.label(minute: minute)) } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.inkMuted) + } + } + .chartYAxis { + AxisMarks(position: .leading, values: unit.agpTicks) { _ in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel().font(LoopDesign.Typeface.caption).foregroundStyle(P.inkMuted) + } + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(accessibilitySummary) + } + + private var accessibilitySummary: String { + guard enoughDays, let high = slots.max(by: { $0.p50 < $1.p50 }), let low = slots.min(by: { $0.p50 < $1.p50 }) else { + return NSLocalizedString("Daily pattern: not enough days", comment: "VoiceOver label for the Trends Daily pattern chart when fewer than 5 days have readings") + } + let span = String.localizedStringWithFormat(NSLocalizedString("%lld days", comment: "A number of days, e.g. a Trends period or how many days are averaged. (1: number of days)"), days) + return String(format: NSLocalizedString("Daily pattern over %1$@. Median highest %2$@ at %3$@, lowest %4$@ at %5$@", comment: "VoiceOver label for the Trends Daily pattern chart. (1: days with readings, e.g. 14 days; 2: highest median glucose; 3: time of day; 4: lowest median glucose; 5: time of day)"), + span, unit.format(high.p50), Self.label(minute: high.minute), unit.format(low.p50), Self.label(minute: low.minute)) + } +} + +// MARK: - InsulinDailyTotals + +struct InsulinDailyTotalsView: View { + let totals: [LoopHistoryMath.DayTotal] + /// Weekly averages instead of days, for periods past 30 days. + let weekly: Bool + /// Calculated from the original daily totals, even when the bars are weekly averages. + let average: Double + var height: CGFloat = 170 + var onSelectDay: ((Date) -> Void)? = nil + + private var yMax: Double { + let top = max(totals.map(\.total).max() ?? 0, average) + return max(10, IOBCOBChartView.niceStep(top / 4) * 5) + } + + var body: some View { + if totals.allSatisfy({ $0.total == 0 }) { + ChartPlaceholder(message: NSLocalizedString("No insulin recorded in this period", comment: "Trends Insulin per day chart placeholder when no insulin was delivered in the period"), height: height) + } else { + chart.frame(height: height) + } + } + + private var unitWidth: Calendar.Component { weekly ? .weekOfYear : .day } + + private var chart: some View { + Chart { + ForEach(totals) { day in + BarMark(x: .value("Day", day.day, unit: unitWidth), yStart: .value("Base", 0), yEnd: .value("Basal", day.basal), width: .ratio(0.7)) + .foregroundStyle(P.basal) + BarMark(x: .value("Day", day.day, unit: unitWidth), yStart: .value("Basal", max(0, day.basal - yMax * 0.006)), yEnd: .value("Edge", day.basal), width: .ratio(0.7)) + .foregroundStyle(P.basalEdge) + BarMark(x: .value("Day", day.day, unit: unitWidth), yStart: .value("Basal", day.basal), yEnd: .value("Total", day.total), width: .ratio(0.7)) + .foregroundStyle(P.insulin) + } + RuleMark(y: .value("Average", average)) + .foregroundStyle(P.ink) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [4, 3])) + .annotation(position: .top, alignment: .trailing, spacing: 2) { + Text(LoopFormat.number(average, decimals: 1)) + .font(LoopDesign.Typeface.caption.weight(.semibold)) + .foregroundStyle(P.ink) + } + } + .chartYScale(domain: 0...yMax) + .chartXAxis { + AxisMarks(values: axisDates) { value in + AxisValueLabel(centered: true) { + if let date = value.as(Date.self) { + Text(axisLabel(date)) + .multilineTextAlignment(.center) + } + } + .font(LoopDesign.Typeface.caption) + .foregroundStyle(P.inkMuted) + } + } + .chartYAxis { + AxisMarks(position: .leading) { _ in + AxisGridLine().foregroundStyle(P.grid) + AxisValueLabel().font(LoopDesign.Typeface.caption).foregroundStyle(P.inkMuted) + } + } + .chartOverlay { proxy in + GeometryReader { geometry in + Rectangle().fill(.clear).contentShape(Rectangle()) + .onTapGesture { location in + guard let onSelectDay, !weekly, let frame = proxy.plotFrame else { return } + let x = location.x - geometry[frame].origin.x + if let date: Date = proxy.value(atX: x), + let day = totals.min(by: { abs($0.day.addingTimeInterval(43200).timeIntervalSince(date)) < abs($1.day.addingTimeInterval(43200).timeIntervalSince(date)) }) { + onSelectDay(day.day) + } + } + } + } + .accessibilityElement(children: .ignore) + .accessibilityLabel(String(format: weekly + ? NSLocalizedString("Insulin per day, weekly average, average %1$@", comment: "VoiceOver label for the Trends Insulin per day chart when bars are weekly averages. (1: average insulin per day, e.g. 32.1 U)") + : NSLocalizedString("Insulin per day, average %1$@", comment: "VoiceOver label for the Trends Insulin per day chart. (1: average insulin per day, e.g. 32.1 U)"), + LoopFormat.totalUnits(average))) + } + + private var axisDates: [Date] { + if weekly { + let stride = max(1, Int(ceil(Double(totals.count) / 6))) + return totals.enumerated().compactMap { index, total in index % stride == 0 ? total.day : nil } + } + if totals.count > 14 { + return totals.map(\.day).filter { Calendar.current.component(.weekday, from: $0) == 2 } + } + return totals.map(\.day) + } + + private func axisLabel(_ date: Date) -> String { + if weekly { + return date.formatted(.dateTime.day().month(.abbreviated)) + } + let weekday = String(date.formatted(.dateTime.weekday(.narrow))) + if totals.count <= 14 { + let first = totals.first?.day == date, last = totals.last?.day == date + let isMonday = Calendar.current.component(.weekday, from: date) == 2 + return first || last || isMonday ? "\(weekday)\n\(date.formatted(.dateTime.day()))" : weekday + } + // 30 days: label every Monday only. + return Calendar.current.component(.weekday, from: date) == 2 ? date.formatted(.dateTime.day().month(.abbreviated)) : "" + } +} + +// MARK: - LoopModeBar + +struct LoopModeBarView: View { + let spans: [LoopModeSpan] + + private var total: TimeInterval { spans.reduce(0) { $0 + $1.duration } } + + static func color(_ mode: LoopModeSpan.Mode) -> Color { + switch mode { + case .closed: return P.statusAutomated + case .limited: return P.statusWarning + case .open: return P.statusCritical + } + } + + static func name(_ mode: LoopModeSpan.Mode) -> String { + switch mode { + case .closed: return NSLocalizedString("Closed loop", comment: "Trends Loop status: time Loop was running in closed loop") + case .limited: return NSLocalizedString("Limited", comment: "Trends Loop status: time closed loop was on but Loop wasn't completing runs") + case .open: return NSLocalizedString("Open loop / manual", comment: "Trends Loop status: time closed loop was switched off") + } + } + + private let modes: [LoopModeSpan.Mode] = [.closed, .limited, .open] + + var body: some View { + if total <= 0 { + ChartPlaceholder(message: NSLocalizedString("No loop runs recorded in this period", comment: "Trends Loop status placeholder when there is no Loop run history for the period"), height: 60) + } else { + VStack(spacing: LoopDesign.Space.s3) { + bar.frame(height: 10) + ForEach(modes, id: \.self) { mode in + row(mode) + } + } + } + } + + private func fraction(_ mode: LoopModeSpan.Mode) -> Double { + LoopHistoryMath.duration(of: mode, in: spans) / total + } + + private var bar: some View { + GeometryReader { geometry in + let minimum: CGFloat = 4 + let widths = modes.map { fraction($0) > 0 ? max(minimum, fraction($0) * geometry.size.width) : 0 } + let excess = widths.reduce(0, +) - geometry.size.width + HStack(spacing: 1) { + ForEach(Array(modes.enumerated()), id: \.offset) { index, mode in + if widths[index] > 0 { + Rectangle() + .fill(Self.color(mode)) + .frame(width: max(0, index == 0 ? widths[index] - excess - 2 : widths[index])) + } + } + } + .clipShape(Capsule()) + } + .accessibilityHidden(true) + } + + private func row(_ mode: LoopModeSpan.Mode) -> some View { + let duration = LoopHistoryMath.duration(of: mode, in: spans) + return HStack(spacing: LoopDesign.Space.s2) { + Circle().fill(Self.color(mode)).frame(width: 8, height: 8) + Text(Self.name(mode)) + .font(LoopDesign.Typeface.subhead) + .foregroundStyle(P.ink) + Text("· \(LoopFormat.duration(duration))") + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + Spacer() + Text(percentText(fraction(mode) * 100, decimals: 1)) + .font(LoopDesign.Typeface.statValueSmall) + .foregroundStyle(P.ink) + } + .accessibilityElement(children: .combine) + } +} + +struct LoopGapsList: View { + let spans: [LoopModeSpan] + + private var gaps: [LoopModeSpan] { + spans.filter { $0.mode != .closed }.sorted { $0.start > $1.start } + } + + var body: some View { + List { + if gaps.isEmpty { + Text(NSLocalizedString("No gaps: Loop ran closed loop all through this period.", comment: "Trends Gaps list when Loop was in closed loop for the whole period")) + .foregroundStyle(P.inkMuted) + } + ForEach(Array(gaps.enumerated()), id: \.offset) { _, gap in + HStack(alignment: .top, spacing: LoopDesign.Space.s3) { + Circle().fill(LoopModeBarView.color(gap.mode)).frame(width: 8, height: 8).padding(.top, 6) + VStack(alignment: .leading, spacing: 2) { + Text(gap.cause ?? LoopModeBarView.name(gap.mode)) + .font(LoopDesign.Typeface.body) + Text("\(gap.start.formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated).hour().minute())) · \(LoopFormat.duration(gap.duration))") + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + } + .accessibilityElement(children: .combine) + } + } + .navigationTitle(NSLocalizedString("Gaps", comment: "Trends Loop status button and screen title: list of times Loop wasn't in closed loop")) + .navigationBarTitleDisplayMode(.inline) + } +} diff --git a/Loop/Redesign/TrendsScreen.swift b/Loop/Redesign/TrendsScreen.swift new file mode 100644 index 0000000000..12919c8e7b --- /dev/null +++ b/Loop/Redesign/TrendsScreen.swift @@ -0,0 +1,475 @@ +// +// TrendsScreen.swift +// Loop +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import SwiftUI +import UIKit + +private typealias P = LoopDesign.Palette + +/// The period review: everything on the screen follows one RangeSelector period. +@MainActor +final class TrendsModel: ObservableObject { + + struct Summary { + var interval: DateInterval + var unit: GlucoseUnitStyle + var glucose: [GlucosePoint] = [] + var stats: LoopHistoryMath.GlucoseStats? + var cgmActive: Double = 0 + var timeInRange: [LoopHistoryMath.RangeBand: Double] = [:] + var agp: [LoopHistoryMath.AGPSlot] = [] + var agpDays = 0 + var totals: [LoopHistoryMath.DayTotal] = [] + /// Carbs and bolus counts cover only the days per-day figures divide by (see `dataDays`). + var carbGrams = 0.0 + var carbEntries = 0 + var carbsByDay: [Date: Double] = [:] + var manualBoluses = 0 + var automaticBoluses = 0 + var loopSpans: [LoopModeSpan] = [] + var loopCoverageStart: Date? + var targetRange: ClosedRange? + + /// The days per-day figures divide by: insulin's averaging days, or complete days with CGM data when there is + /// no insulin (today only when no complete day has any), never the period length. + var dataDays = 0 + var days: Double { Double(max(1, dataDays)) } + var basalUnits: Double { LoopHistoryMath.averagingDays(totals).reduce(0) { $0 + $1.basal } } + var bolusUnits: Double { LoopHistoryMath.averagingDays(totals).reduce(0) { $0 + $1.bolus } } + var insulinPerDay: Double { LoopHistoryMath.averageDailyInsulin(totals) } + var basalShare: Double { basalUnits + bolusUnits > 0 ? basalUnits / (basalUnits + bolusUnits) : 0 } + } + + @Published var period: TrendsPeriod = .twoWeeks + @Published var endDay = Date() + @Published private(set) var summary: Summary? + @Published private(set) var loading = false + @Published private(set) var loadError: String? + + let provider: LoopHistoryProvider + private var loadTask: Task? + + init(provider: LoopHistoryProvider) { + self.provider = provider + } + + var interval: DateInterval { period.interval(endingOn: endDay) } + + func reload() { + loadTask?.cancel() + let interval = self.interval + loading = true + summary = nil + loadError = nil + loadTask = Task { + do { + let result = try await Self.load(provider: provider, interval: interval) + guard !Task.isCancelled else { return } + self.summary = result + } catch { + guard !Task.isCancelled else { return } + self.loadError = error.localizedDescription + } + self.loading = false + } + } + + private static func load(provider: LoopHistoryProvider, interval: DateInterval) async throws -> Summary { + var summary = Summary(interval: interval, unit: provider.unitStyle) + summary.targetRange = provider.glucoseTargetRange + + async let historyFetch = provider.dayHistory(interval, includeOnBoard: false) + async let runsFetch = provider.loopRuns() + let history = try await historyFetch + let (runs, coverageStart) = try await runsFetch + + summary.glucose = history.glucose + summary.stats = LoopHistoryMath.glucoseStats(history.glucose) + summary.cgmActive = LoopHistoryMath.cgmActiveFraction(history.glucose, over: interval) + summary.timeInRange = LoopHistoryMath.timeInRange(history.glucose) + summary.agp = LoopHistoryMath.agp(history.glucose) + summary.agpDays = LoopHistoryMath.daysWithReadings(history.glucose) + + let calendar = Calendar.current + summary.totals = LoopHistoryMath.days(in: interval).map { day in + let basal = history.basal.compactMap { $0.clamped(to: day) }.reduce(0) { $0 + $1.units } + let bolus = history.boluses.filter { $0.date >= day.start && $0.date < day.end }.reduce(0) { $0 + $1.units } + return LoopHistoryMath.DayTotal(day: day.start, basal: basal, bolus: bolus, + isComplete: calendar.date(byAdding: .day, value: 1, to: day.start) == day.end) + } + let glucoseDays = Set(history.glucose.map { calendar.startOfDay(for: $0.date) }) + // Carbs and bolus counts share insulin's days, so a period with years of CGM data but a few days of Loop + // isn't spread thin. Without insulin, fall back to days with CGM data. + let withData = summary.totals.filter { $0.total > 0 || glucoseDays.contains($0.day) } + let insulinDays = LoopHistoryMath.averagingDays(summary.totals) + let averaged = !insulinDays.isEmpty ? insulinDays + : withData.contains(where: \.isComplete) ? withData.filter(\.isComplete) : withData + let averagedDays = Set(averaged.map(\.day)) + let inAveragedDays: (Date) -> Bool = { averagedDays.contains(calendar.startOfDay(for: $0)) } + summary.dataDays = averaged.count + summary.carbsByDay = Dictionary(grouping: history.carbs) { calendar.startOfDay(for: $0.date) } + .mapValues { $0.reduce(0) { $0 + $1.grams } } + let carbs = history.carbs.filter { inAveragedDays($0.date) } + summary.carbGrams = carbs.reduce(0) { $0 + $1.grams } + summary.carbEntries = carbs.count + let boluses = history.boluses.filter { inAveragedDays($0.date) } + summary.manualBoluses = boluses.filter { !$0.automatic }.count + summary.automaticBoluses = boluses.filter(\.automatic).count + + summary.loopCoverageStart = coverageStart + summary.loopSpans = LoopHistoryMath.loopModeSpans(interval: interval, runs: runs, modeChanges: LoopModeHistory.shared.changes, + coverageStart: coverageStart) + return summary + } + + // MARK: Tiles + + func tiles(_ s: Summary) -> [StatTile] { + let unit = s.unit + var tiles: [StatTile] = [] + let averageLabel = NSLocalizedString("Average", comment: "Trends summary tile: mean glucose over the period") + let gmiLabel = NSLocalizedString("GMI", comment: "Trends summary tile: abbreviation for Glucose Management Indicator, an estimate of HbA1c from CGM data") + let loopActiveLabel = NSLocalizedString("Loop active", comment: "Trends summary tile: share of the period Loop spent in closed loop") + if let stats = s.stats { + tiles.append(StatTile(label: averageLabel, value: unit.format(stats.meanMgdl), unit: unit.unitName, + detail: String(format: NSLocalizedString("SD %1$@ · CV %2$@%%", comment: "Trends Average tile detail: standard deviation and coefficient of variation of glucose. (1: standard deviation in the glucose unit, 2: coefficient of variation as a percentage number)"), + unit.format(stats.sdMgdl), LoopFormat.number(stats.cv * 100, decimals: 0)))) + let enough = s.cgmActive * s.interval.duration / 86400 >= 10 + tiles.append(StatTile(label: gmiLabel, value: LoopFormat.number(stats.gmiPercent, decimals: 1), unit: "%", + detail: enough + ? String(format: NSLocalizedString("%1$@ mmol/mol", comment: "Trends GMI tile detail: the GMI in IFCC units. (1: value)"), + LoopFormat.number(stats.gmiMmolMol, decimals: 0)) + : NSLocalizedString("Needs 10 days of CGM", comment: "Trends GMI tile detail when fewer than 10 days of CGM data are available"))) + } else { + tiles.append(StatTile(label: averageLabel, value: "–", unit: unit.unitName, + detail: NSLocalizedString("No CGM data", comment: "Trends Average tile detail when the period has no glucose readings"))) + tiles.append(StatTile(label: gmiLabel, value: "–", unit: "%", detail: nil)) + } + let basalPercent = LoopFormat.number(s.basalShare * 100, decimals: 0) + let insulinDetail: String + if let note = daysNote(s) { + insulinDetail = String(format: NSLocalizedString("%1$@%% basal · %2$@", comment: "Trends Insulin per day tile detail when only some days are averaged. (1: basal share as a percentage number, 2: days averaged, e.g. 5 of 14 days)"), + basalPercent, note) + } else { + insulinDetail = String(format: NSLocalizedString("%1$@%% basal", comment: "Trends Insulin per day tile detail: share of insulin delivered as basal. (1: percentage number)"), + basalPercent) + } + tiles.append(StatTile(label: NSLocalizedString("Insulin per day", comment: "Trends tile and card title: average total insulin per day"), + value: LoopFormat.number(s.insulinPerDay, decimals: 1), + unit: NSLocalizedString("U", comment: "Abbreviation for insulin units"), + detail: insulinDetail)) + tiles.append(StatTile(label: NSLocalizedString("Carbs per day", comment: "Trends summary tile: average grams of carbohydrate entered per day"), + value: LoopFormat.number(s.carbGrams / s.days, decimals: 0), + unit: NSLocalizedString("g", comment: "Abbreviation for grams"), + detail: String(format: NSLocalizedString("%1$@ entries", comment: "Trends Carbs per day tile detail: average number of carb entries per day, a fractional value such as 2.5, so not pluralised. (1: number with one decimal)"), + LoopFormat.number(Double(s.carbEntries) / s.days, decimals: 1)))) + tiles.append(StatTile(label: NSLocalizedString("Boluses per day", comment: "Trends summary tile: average number of manual boluses per day"), + value: LoopFormat.number(Double(s.manualBoluses) / s.days, decimals: 1), unit: nil, + detail: String(format: NSLocalizedString("+ %1$@ automatic", comment: "Trends Boluses per day tile detail: average number of automatic boluses per day on top of the manual ones, a fractional value such as 4.2. (1: number with one decimal)"), + LoopFormat.number(Double(s.automaticBoluses) / s.days, decimals: 1)))) + let covered = s.loopSpans.reduce(0) { $0 + $1.duration } + if covered > 0 { + let closed = LoopHistoryMath.duration(of: .closed, in: s.loopSpans) + tiles.append(StatTile(label: loopActiveLabel, value: LoopFormat.number(closed / covered * 100, decimals: 0), unit: "%", + detail: String(format: NSLocalizedString("%1$@ of %2$@", comment: "Trends Loop active tile detail: time in closed loop out of the time Loop status is known. (1: duration in closed loop, e.g. 6d 4h, 2: duration covered, e.g. 7d)"), + LoopFormat.duration(closed), LoopFormat.duration(covered)))) + } else { + tiles.append(StatTile(label: loopActiveLabel, value: "–", unit: "%", + detail: NSLocalizedString("No loop runs kept", comment: "Trends Loop active tile detail when no Loop run history is available for the period"))) + } + return tiles + } + + /// "5 of 14 days" when only part of the period is averaged: days without data, or today while it runs. + private func daysNote(_ s: Summary) -> String? { + let insulinDays = LoopHistoryMath.averagingDays(s.totals).count + guard insulinDays < s.totals.count else { return nil } + let total = String.localizedStringWithFormat(NSLocalizedString("%lld days", comment: "A number of days, e.g. a Trends period or how many days are averaged. (1: number of days)"), s.totals.count) + return String(format: NSLocalizedString("%1$@ of %2$@", comment: "Trends: how many days of the period are averaged. (1: days averaged, a number; 2: days in the period, e.g. 14 days)"), LoopFormat.number(Double(insulinDays), decimals: 0), total) + } + + // MARK: Export + + static func exportCSV(_ s: Summary) throws -> URL { + // The CSV header and values are deliberately not localised: fixed English columns and '.' decimals for data interchange. + var lines = ["date,mean_glucose_\(s.unit.isMmol ? "mmol_l" : "mg_dl"),readings,time_in_range_pct,basal_u,bolus_u,total_u,carbs_g"] + let calendar = Calendar.current + let byDay = Dictionary(grouping: s.glucose) { calendar.startOfDay(for: $0.date) } + for total in s.totals { + let readings = byDay[total.day] ?? [] + let mean = readings.isEmpty ? "" : String(format: "%.*f", locale: Locale(identifier: "en_US_POSIX"), + s.unit.isMmol ? 1 : 0, s.unit.value(readings.reduce(0) { $0 + $1.mgdl } / Double(readings.count))) + let tir = readings.isEmpty ? "" : String(format: "%.0f", (LoopHistoryMath.timeInRange(readings)[.inRange] ?? 0) * 100) + let date = Date.ISO8601FormatStyle(timeZone: .current).year().month().day().format(total.day) + let carbs = String(format: "%.0f", s.carbsByDay[total.day] ?? 0) + lines.append("\(date),\(mean),\(readings.count),\(tir),\(String(format: "%.2f,%.2f,%.2f", total.basal, total.bolus, total.total)),\(carbs)") + } + let url = FileManager.default.temporaryDirectory.appendingPathComponent(Self.fileName(s.interval) + ".csv") + try lines.joined(separator: "\n").write(to: url, atomically: true, encoding: .utf8) + return url + } + + func exportPDF(_ s: Summary) throws -> URL { + let url = FileManager.default.temporaryDirectory.appendingPathComponent(Self.fileName(s.interval) + ".pdf") + let report = TrendsReport(summary: s, tiles: tiles(s)) + .frame(width: 560) + .environment(\.colorScheme, .light) + let renderer = ImageRenderer(content: report) + renderer.proposedSize = ProposedViewSize(width: 560, height: nil) + var thrown: Error? + renderer.render { size, draw in + var box = CGRect(x: 0, y: 0, width: 612, height: max(792, size.height + 52)) + guard let consumer = CGDataConsumer(url: url as CFURL), let context = CGContext(consumer: consumer, mediaBox: &box, nil) else { + thrown = CocoaError(.fileWriteUnknown) + return + } + context.beginPDFPage(nil) + context.translateBy(x: 26, y: box.height - size.height - 26) + draw(context) + context.endPDFPage() + context.closePDF() + } + if let thrown { throw thrown } + return url + } + + private static func fileName(_ interval: DateInterval) -> String { + String(format: NSLocalizedString("Loop trends %1$@", comment: "File name of an exported Trends report or CSV, without the extension. (1: date range of the period)"), + fileStamp(interval)) + } + + private static func fileStamp(_ interval: DateInterval) -> String { + LoopFormat.range(interval.start, interval.end.addingTimeInterval(-1)).replacingOccurrences(of: " – ", with: " to ") + } +} + +// MARK: - Screen + +struct TrendsView: View { + @StateObject private var model: TrendsModel + @State private var path: [TrendsRoute] = [] + @State private var exportURL: URL? + @State private var exportError: String? + + enum TrendsRoute: Hashable { + case day(Date) + case gaps + } + + init(provider: LoopHistoryProvider) { + _model = StateObject(wrappedValue: TrendsModel(provider: provider)) + } + + var body: some View { + NavigationStack(path: $path) { + ScrollView { + LazyVStack(alignment: .leading, spacing: LoopDesign.Space.s6, pinnedViews: [.sectionHeaders]) { + Section { + content + } header: { + RangeSelectorView(period: $model.period, endDay: $model.endDay) + .padding(.vertical, LoopDesign.Space.s2) + .background(P.surface) + } + } + .padding(.horizontal, LoopDesign.Space.s4) + .padding(.bottom, LoopDesign.Space.s6) + } + .background(P.surface) + .navigationTitle(NSLocalizedString("Trends", comment: "Title of the Trends tab")) + .refreshable { model.reload() } + .navigationDestination(for: TrendsRoute.self) { route in + switch route { + case .day(let day): + DayDetailView(provider: model.provider, day: day) + case .gaps: + LoopGapsList(spans: model.summary?.loopSpans ?? []) + } + } + } + .onAppear { model.reload() } + .onChange(of: model.period) { _, _ in model.reload() } + .onChange(of: model.endDay) { _, _ in model.reload() } + .sheet(item: $exportURL) { url in + ShareSheet(items: [url]) + } + .alert(NSLocalizedString("Couldn't export", comment: "Alert title when exporting the Trends PDF or CSV fails"), + isPresented: Binding(get: { exportError != nil }, set: { if !$0 { exportError = nil } })) { + Button(NSLocalizedString("OK", comment: "Button to dismiss an alert"), role: .cancel) {} + } message: { + Text(exportError ?? "") + } + } + + @ViewBuilder + private var content: some View { + if let s = model.summary { + summaryCard(s) + LoopCard { + CardHeader(title: NSLocalizedString("Time in range", comment: "Trends card title: share of glucose readings in each range")) { + Text(String(format: NSLocalizedString("%1$@%% CGM active", comment: "Trends Time in range card: share of the period with CGM readings. (1: percentage number)"), + LoopFormat.number(s.cgmActive * 100, decimals: 0))) + } + if s.glucose.isEmpty { + ChartPlaceholder(message: NSLocalizedString("No CGM data in this period", comment: "Trends chart placeholder when the period has no glucose readings")) + } else { + TimeInRangeView(fractions: s.timeInRange, unit: s.unit) + } + Text(String(format: NSLocalizedString("Aim: over 70%% in range, under 4%% low.", comment: "Trends Time in range card footnote: the consensus targets for time in range and time low"))) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + LoopCard { + CardHeader(title: NSLocalizedString("Daily pattern", comment: "Trends card title: the ambulatory glucose profile, glucose by time of day across the period")) { Text(s.unit.unitName) } + AGPChartView(slots: s.agp, readings: s.glucose, days: s.agpDays, unit: s.unit, targetRange: s.targetRange) + ChartLegend(items: [ + LegendItem(swatch: .solid(P.glucose), label: NSLocalizedString("Median", comment: "Trends Daily pattern legend: the median glucose line")), + LegendItem(swatch: .solid(P.agpInner), label: NSLocalizedString("25–75%", comment: "Trends Daily pattern legend: band between the 25th and 75th percentiles of glucose")), + LegendItem(swatch: .solid(P.agpOuter), label: NSLocalizedString("5–95%", comment: "Trends Daily pattern legend: band between the 5th and 95th percentiles of glucose")), + ]) + } + LoopCard { + CardHeader(title: NSLocalizedString("Insulin per day", comment: "Trends tile and card title: average total insulin per day")) { + Text(s.totals.count > 30 + ? NSLocalizedString("per day, weekly average", comment: "Trends Insulin per day card subtitle when each bar is a week's average daily total") + : NSLocalizedString("basal and bolus", comment: "Trends Insulin per day card subtitle when each bar is one day's basal and bolus")) + } + InsulinDailyTotalsView(totals: s.totals.count > 30 ? LoopHistoryMath.weekly(s.totals) : s.totals, + weekly: s.totals.count > 30, average: s.insulinPerDay) { day in + path.append(.day(day)) + } + ChartLegend(items: insulinLegend(s)) + } + LoopCard { + CardHeader(title: NSLocalizedString("Loop status", comment: "Trends card title: how long Loop spent in closed loop, limited or open loop")) { + Button(NSLocalizedString("Gaps", comment: "Trends Loop status button and screen title: list of times Loop wasn't in closed loop")) { path.append(.gaps) } + .foregroundStyle(P.accentInk) + .disabled(s.loopSpans.isEmpty) + } + LoopModeBarView(spans: s.loopSpans) + if let note = coverageNote(s) { + Text(note) + .font(LoopDesign.Typeface.footnote) + .foregroundStyle(P.inkMuted) + } + } + } else if let error = model.loadError { + LoopCard { + ChartPlaceholder(message: String(format: NSLocalizedString("Couldn't load Trends: %1$@", comment: "Trends error message when the history can't be read. (1: error description)"), error)) + Button(NSLocalizedString("Retry", comment: "Button to try loading Trends again after an error")) { model.reload() }.foregroundStyle(P.accentInk) + } + } else { + ProgressView().frame(maxWidth: .infinity, minHeight: 300) + } + } + + private func summaryCard(_ s: TrendsModel.Summary) -> some View { + LoopCard { + CardHeader(title: NSLocalizedString("Summary", comment: "Trends card title: the summary statistics tiles")) { + Menu(NSLocalizedString("Export", comment: "Trends menu title: export the period as a PDF report or CSV file")) { + Button(NSLocalizedString("PDF report", comment: "Trends export menu item: share a PDF report of the period")) { export { try model.exportPDF(s) } } + Button(NSLocalizedString("CSV, one row per day", comment: "Trends export menu item: share a CSV spreadsheet file with one row for each day")) { export { try TrendsModel.exportCSV(s) } } + } + .foregroundStyle(P.accentInk) + } + StatGridView(tiles: model.tiles(s)) + .opacity(model.loading ? 0.5 : 1) + } + } + + private func export(_ make: () throws -> URL) { + do { + exportURL = try make() + } catch { + exportError = error.localizedDescription + } + } + + private func insulinLegend(_ s: TrendsModel.Summary) -> [LegendItem] { + let total = s.basalUnits + s.bolusUnits + let days = Double(max(1, LoopHistoryMath.averagingDays(s.totals).count)) + let bolusShare = total > 0 ? Int((s.bolusUnits / total * 100).rounded()) : 0 + let basalShare = total > 0 ? 100 - bolusShare : 0 + return [ + LegendItem(swatch: .solid(P.insulin), + label: String(format: NSLocalizedString("Bolus %1$@ U (%2$@%%)", comment: "Trends Insulin per day legend: average bolus insulin per day and its share of the total. (1: units, 2: percentage number)"), + LoopFormat.number(s.bolusUnits / days, decimals: 1), LoopFormat.number(Double(bolusShare), decimals: 0))), + LegendItem(swatch: .basal, + label: String(format: NSLocalizedString("Basal %1$@ U (%2$@%%)", comment: "Trends Insulin per day legend: average basal insulin per day and its share of the total. (1: units, 2: percentage number)"), + LoopFormat.number(s.basalUnits / days, decimals: 1), LoopFormat.number(Double(basalShare), decimals: 0))), + LegendItem(swatch: .dash(P.ink), + label: String(format: NSLocalizedString("Average %1$@ U", comment: "Trends Insulin per day legend: the dashed line showing average total insulin per day. (1: units)"), + LoopFormat.number(s.insulinPerDay, decimals: 1))), + ] + } + + private func coverageNote(_ s: TrendsModel.Summary) -> String? { + guard let start = s.loopSpans.first?.start else { + return NSLocalizedString("Loop status is recorded from when the new interface was first opened.", comment: "Trends Loop status footnote when there is no Loop status history yet") + } + guard start > s.interval.start else { return nil } + return String(format: NSLocalizedString("Covers %1$@: Loop keeps 7 days of runs, and closed or open loop is recorded from when the new interface was first opened.", comment: "Trends Loop status footnote when the status covers only part of the period. (1: date range covered)"), + LoopFormat.range(start, s.interval.end)) + } +} + +extension URL: @retroactive Identifiable { + public var id: String { absoluteString } +} + +struct ShareSheet: UIViewControllerRepresentable { + let items: [Any] + + func makeUIViewController(context: Context) -> UIActivityViewController { + UIActivityViewController(activityItems: items, applicationActivities: nil) + } + + func updateUIViewController(_ controller: UIActivityViewController, context: Context) {} +} + +// MARK: - PDF report + +/// The Trends cards laid out for paper. +private struct TrendsReport: View { + let summary: TrendsModel.Summary + let tiles: [StatTile] + + var body: some View { + VStack(alignment: .leading, spacing: LoopDesign.Space.s4) { + VStack(alignment: .leading, spacing: 2) { + Text(NSLocalizedString("Loop trends", comment: "Title of the exported Trends PDF report")).font(.title2.bold()) + Text(LoopFormat.range(summary.interval.start, summary.interval.end.addingTimeInterval(-1))) + .font(.subheadline) + .foregroundStyle(P.inkMuted) + } + StatGridView(tiles: tiles) + HStack(alignment: .top, spacing: LoopDesign.Space.s4) { + VStack(alignment: .leading, spacing: LoopDesign.Space.s2) { + Text(NSLocalizedString("Time in range", comment: "Trends card title: share of glucose readings in each range")).font(.headline) + TimeInRangeView(fractions: summary.timeInRange, unit: summary.unit) + } + .frame(maxWidth: .infinity) + } + VStack(alignment: .leading, spacing: LoopDesign.Space.s2) { + Text(NSLocalizedString("Daily pattern", comment: "Trends card title: the ambulatory glucose profile, glucose by time of day across the period")).font(.headline) + AGPChartView(slots: summary.agp, readings: summary.glucose, days: summary.agpDays, unit: summary.unit, + targetRange: summary.targetRange, height: 160) + } + VStack(alignment: .leading, spacing: LoopDesign.Space.s2) { + Text(NSLocalizedString("Insulin per day", comment: "Trends tile and card title: average total insulin per day")).font(.headline) + InsulinDailyTotalsView(totals: summary.totals.count > 30 ? LoopHistoryMath.weekly(summary.totals) : summary.totals, + weekly: summary.totals.count > 30, average: summary.insulinPerDay, height: 140) + } + VStack(alignment: .leading, spacing: LoopDesign.Space.s2) { + Text(NSLocalizedString("Loop status", comment: "Trends card title: how long Loop spent in closed loop, limited or open loop")).font(.headline) + LoopModeBarView(spans: summary.loopSpans) + } + } + .padding(LoopDesign.Space.s2) + .background(Color.white) + } +} diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index 580d67eb8a..a1df12c820 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -54,6 +54,7 @@ final class StatusTableViewController: LoopChartsTableViewController { tableView.register(BolusProgressTableViewCell.nib(), forCellReuseIdentifier: BolusProgressTableViewCell.className) tableView.register(AlertPermissionsDisabledWarningCell.self, forCellReuseIdentifier: AlertPermissionsDisabledWarningCell.className) tableView.register(MuteAlertsWarningCell.self, forCellReuseIdentifier: MuteAlertsWarningCell.className) + tableView.register(UITableViewCell.self, forCellReuseIdentifier: Self.nowHostingCellIdentifier) if FeatureFlags.predictedGlucoseChartClampEnabled { statusCharts.glucose.glucoseDisplayRange = LoopConstants.glucoseChartDefaultDisplayBoundClamped @@ -120,16 +121,16 @@ final class StatusTableViewController: LoopChartsTableViewController { automaticDosingStatus.$automaticDosingEnabled .receive(on: DispatchQueue.main) - .sink { self.automaticDosingStatusChanged($0) } + .sink { [weak self] in self?.automaticDosingStatusChanged($0) } .store(in: &cancellables) alertMuter.$configuration .removeDuplicates() .receive(on: RunLoop.main) .dropFirst() - .sink { _ in - self.refreshContext.update(with: .status) - self.reloadData(animated: true) + .sink { [weak self] _ in + self?.refreshContext.update(with: .status) + self?.reloadData(animated: true) } .store(in: &cancellables) @@ -145,7 +146,11 @@ final class StatusTableViewController: LoopChartsTableViewController { addScenarioStepGestureRecognizers() tableView.backgroundColor = .secondarySystemBackground - + + if usesRedesign { + tableView.backgroundColor = .systemGroupedBackground + tableView.separatorStyle = .none + } } override func didReceiveMemoryWarning() { @@ -162,7 +167,7 @@ final class StatusTableViewController: LoopChartsTableViewController { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(true, animated: animated) - navigationController?.setToolbarHidden(false, animated: animated) + navigationController?.setToolbarHidden(usesRedesign, animated: animated) updateToolbarItems() @@ -263,6 +268,33 @@ final class StatusTableViewController: LoopChartsTableViewController { private var bolusProgressReporter: DoseProgressReporter? + // MARK: - Redesign + + /// Read once, so a table never mixes the two layouts; LoopAppManager rebuilds the screen when the preference changes. + let usesRedesign = LoopInterfacePreference.useRedesign + + private static let nowHostingCellIdentifier = "NowHostingCell" + + private lazy var nowModel: NowModel = { + let model = NowModel(deviceManager: deviceManager, automaticDosingStatus: automaticDosingStatus) + model.isOnboardingComplete = { [weak self] in self?.onboardingManager.isComplete ?? false } + return model + }() + + private lazy var nowActions = NowActions( + addCarbs: { [weak self] in self?.userTappedAddCarbs() }, + bolus: { [weak self] in self?.presentBolusScreen() }, + togglePreMeal: { [weak self] in self?.togglePreMealMode(confirm: false) }, + customPresets: { [weak self] in self?.presentCustomPresets(confirm: false) }, + showPrediction: { [weak self] in self?.showPredictionFromNow() }, + showToday: { [weak self] in self?.showDay(Date()) }, + showInsulin: { [weak self] in self?.performSegue(withIdentifier: InsulinDeliveryTableViewController.className, sender: self) }, + showCarbs: { [weak self] in self?.performSegue(withIdentifier: CarbAbsorptionViewController.className, sender: self) }, + pumpTapped: { [weak self] in self?.executeHUDTapAction(self?.deviceManager.didTapOnPumpStatus(), from: self?.view) }, + cgmTapped: { [weak self] in self?.executeHUDTapAction(self?.deviceManager.didTapOnCGMStatus(), from: self?.view) }, + loopStatusTapped: { [weak self] in self?.showLoopStatusFromNow() } + ) + private func updateBolusProgress() { if let cell = tableView.cellForRow(at: IndexPath(row: StatusRow.status.rawValue, section: Section.status.rawValue)) as? BolusProgressTableViewCell { cell.deliveredUnits = bolusProgressReporter?.progress.deliveredUnits @@ -360,11 +392,11 @@ final class StatusTableViewController: LoopChartsTableViewController { private var refreshContext = RefreshContext.all private var shouldShowHUD: Bool { - return !landscapeMode + return !landscapeMode && !usesRedesign } private var shouldShowStatus: Bool { - return !landscapeMode && statusRowMode.hasRow + return (!landscapeMode || usesRedesign) && statusRowMode.hasRow } override func glucoseUnitDidChange() { @@ -675,6 +707,10 @@ final class StatusTableViewController: LoopChartsTableViewController { self.tableView.endUpdates() + if self.usesRedesign { + self.nowModel.refresh() + } + self.reloading = false let reloadNow = !self.refreshContext.isEmpty self.refreshContext.formUnion(retryContext) @@ -690,8 +726,10 @@ final class StatusTableViewController: LoopChartsTableViewController { private enum Section: Int, CaseIterable { case alertWarning case hud + case nowHeader case status case charts + case nowCharts } // MARK: - Chart Section Data @@ -916,9 +954,11 @@ final class StatusTableViewController: LoopChartsTableViewController { case .hud: return shouldShowHUD ? 1 : 0 case .charts: - return ChartRow.allCases.count + return usesRedesign ? 0 : ChartRow.allCases.count case .status: return shouldShowStatus ? StatusRow.allCases.count : 0 + case .nowHeader, .nowCharts: + return usesRedesign ? 1 : 0 } } @@ -1020,6 +1060,10 @@ final class StatusTableViewController: LoopChartsTableViewController { hudView = cell.hudView return cell + case .nowHeader: + return nowHostingCell(for: indexPath) { NowHeaderView(model: self.nowModel, actions: self.nowActions) } + case .nowCharts: + return nowHostingCell(for: indexPath) { NowChartsView(model: self.nowModel, actions: self.nowActions) } case .charts: let cell = tableView.dequeueReusableCell(withIdentifier: ChartTableViewCell.className, for: indexPath) as! ChartTableViewCell @@ -1207,7 +1251,7 @@ final class StatusTableViewController: LoopChartsTableViewController { cell.setSubtitleLabel(label: nil) } } - case .hud, .status, .alertWarning: + case .hud, .status, .alertWarning, .nowHeader, .nowCharts: break } } @@ -1228,7 +1272,7 @@ final class StatusTableViewController: LoopChartsTableViewController { case .iob, .dose, .cob: return max(106, 0.21 * availableSize) } - case .hud, .status, .alertWarning: + case .hud, .status, .alertWarning, .nowHeader, .nowCharts: return UITableView.automaticDimension } } @@ -1243,7 +1287,7 @@ final class StatusTableViewController: LoopChartsTableViewController { tableView.deselectRow(at: indexPath, animated: true) presentUnmuteAlertConfirmation() } - case .hud: + case .hud, .nowHeader, .nowCharts: break case .status: switch StatusRow(rawValue: indexPath.row)! { @@ -2258,3 +2302,83 @@ extension StatusTableViewController: ServicesViewModelDelegate { show(settingsViewController, sender: self) } } + +// MARK: - Redesigned Now screen + +extension StatusTableViewController { + /// In the new interface the status row (bolus progress, suspended, presets, no recent glucose) sits between two + /// SwiftUI cards, so it takes the same shape instead of spanning the screen. + override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + guard usesRedesign, Section(rawValue: indexPath.section) == .status else { return } + cell.backgroundColor = .clear + cell.backgroundView = NowCardBackgroundView() + let margins = NSDirectionalEdgeInsets(top: 10, leading: 32, bottom: 10, trailing: 32) + cell.preservesSuperviewLayoutMargins = false + cell.directionalLayoutMargins = margins + cell.contentView.preservesSuperviewLayoutMargins = false + cell.contentView.directionalLayoutMargins = margins + } + + private func nowHostingCell(for indexPath: IndexPath, @ViewBuilder content: () -> Content) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: Self.nowHostingCellIdentifier, for: indexPath) + cell.selectionStyle = .none + cell.backgroundColor = .clear + cell.contentConfiguration = UIHostingConfiguration(content: content).margins(.all, 0) + return cell + } + + func presentSettingsFromTab() { + if presentedViewController != nil { + return + } + presentSettings() + } + + private func showPredictionFromNow() { + guard automaticDosingStatus.automaticDosingEnabled || !FeatureFlags.simpleBolusCalculatorEnabled else { return } + performSegue(withIdentifier: PredictionTableViewController.className, sender: self) + } + + func showDay(_ day: Date) { + let detail = UIHostingController(rootView: DayDetailView(provider: nowModel.provider, day: day)) + navigationController?.pushViewController(detail, animated: true) + } + + private func showLoopStatusFromNow() { + let lastCompleted = deviceManager.loopManager.lastLoopCompleted + if let deviceError = deviceManager.lastError, deviceError.date > (lastCompleted ?? .distantPast) { + showLastError(self) + } else if lastLoopError != nil { + showLastError(self) + } else if let lastCompleted { + let mode = automaticDosingStatus.automaticDosingEnabled + ? NSLocalizedString("Closed loop is on.", comment: "Message in the alert shown when tapping the Loop status on the Now screen while closed loop is on") + : NSLocalizedString("Closed loop is off: Loop recommends but doesn't adjust insulin.", comment: "Message in the alert shown when tapping the Loop status on the Now screen while closed loop is off") + presentLoopCompletionMessage(title: String(format: NSLocalizedString("Loop ran at %1$@", comment: "Title of the alert shown when tapping the Loop status on the Now screen. (1: time Loop last completed, e.g. 14:05)"), LoopFormat.time(lastCompleted)), message: mode) + } else { + presentLoopCompletionMessage(title: NSLocalizedString("Loop hasn't run yet", comment: "Title of the alert shown when tapping the Loop status on the Now screen before Loop has ever completed"), message: NSLocalizedString("Loop runs when it has a new CGM reading and can reach the pump.", comment: "Message in the alert shown when tapping the Loop status on the Now screen before Loop has ever completed")) + } + } +} + +/// A raised, rounded card inset like the SwiftUI cards on the Now screen. +private final class NowCardBackgroundView: UIView { + private let card = UIView() + + override init(frame: CGRect) { + super.init(frame: frame) + card.backgroundColor = .secondarySystemGroupedBackground + card.layer.cornerRadius = 14 + card.layer.cornerCurve = .continuous + addSubview(card) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + card.frame = bounds.inset(by: UIEdgeInsets(top: 4, left: 16, bottom: 4, right: 16)) + } +} diff --git a/Loop/Views/SettingsView.swift b/Loop/Views/SettingsView.swift index 9f9e3aa069..62bef86780 100644 --- a/Loop/Views/SettingsView.swift +++ b/Loop/Views/SettingsView.swift @@ -77,6 +77,7 @@ public struct SettingsView: View { dosingStrategySection } alertManagementSection + interfaceSection if viewModel.pumpManagerSettingsViewModel.isSetUp() { configurationSection } @@ -269,6 +270,21 @@ extension SettingsView { .environment(\.insulinTintColor, self.insulinTintColor) } + @ViewBuilder + private var interfaceSection: some View { + Section(footer: Text(NSLocalizedString("The new interface adds Trends and Logbook tabs. Turn it off to go back to the classic status screen; Settings closes to switch.", comment: "Footer for the interface choice in settings"))) { + Toggle(NSLocalizedString("New Interface", comment: "Title of the toggle for the redesigned interface"), isOn: Binding( + get: { LoopInterfacePreference.useRedesign }, + set: { LoopInterfacePreference.useRedesign = $0 } + )) + } + Section { + NavigationLink(destination: AppearanceSettingsView()) { + Text(NSLocalizedString("Appearance and App Icon", comment: "Title of the row that opens the appearance and app icon settings")) + } + } + } + private var configurationSection: some View { Section(header: SectionHeader(label: NSLocalizedString("Configuration", comment: "The title of the Configuration section in settings"))) { NavigationLink(destination: therapySettingsView) { diff --git a/LoopCore/NSUserDefaults.swift b/LoopCore/NSUserDefaults.swift index dacf2ecdc7..9ecd83aa7a 100644 --- a/LoopCore/NSUserDefaults.swift +++ b/LoopCore/NSUserDefaults.swift @@ -24,6 +24,7 @@ extension UserDefaults { case LastMissedMealNotification = "com.loopkit.Loop.lastMissedMealNotification" case userRequestedLoopReset = "com.loopkit.Loop.userRequestedLoopReset" case liveActivity = "com.loopkit.Loop.liveActivity" + case redesignEnabled = "com.loopkit.Loop.redesign.enabled" } public static let appGroup = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) @@ -167,6 +168,13 @@ extension UserDefaults { } } + /// Whether the redesigned interface is on. The app mirrors its setting into the app group so the + /// widget and Live Activity can match it; they default to the redesign, as the app does. + public var redesignEnabled: Bool { + get { object(forKey: Key.redesignEnabled.rawValue) as? Bool ?? true } + set { set(newValue, forKey: Key.redesignEnabled.rawValue) } + } + public var liveActivity: LiveActivitySettings? { get { let decoder = JSONDecoder() diff --git a/LoopTests/Models/LoopHistoryMathTests.swift b/LoopTests/Models/LoopHistoryMathTests.swift new file mode 100644 index 0000000000..2b96f68e61 --- /dev/null +++ b/LoopTests/Models/LoopHistoryMathTests.swift @@ -0,0 +1,259 @@ +// +// LoopHistoryMathTests.swift +// LoopTests +// +// Copyright © 2026 LoopKit Authors. All rights reserved. +// + +import XCTest +import HealthKit +import LoopKit +@testable import Loop + +class LoopHistoryMathTests: XCTestCase { + + private let start = Date(timeIntervalSinceReferenceDate: 800_000_000) + private func at(_ minutes: Double) -> Date { start.addingTimeInterval(minutes * 60) } + + // MARK: Basal + + func testBasalGapsDoNotInventDelivery() { + let window = DateInterval(start: at(0), end: at(120)) + let schedule = [LoopHistoryMath.ScheduleValue(start: at(-60), end: at(240), rate: 1.0)] + let temp = LoopHistoryMath.BasalDelivery(start: at(60), end: at(90), rate: 2.0, kind: .temp, automatic: true) + let segments = LoopHistoryMath.basalSegments(window: window, schedule: schedule, deliveries: [temp]) + XCTAssertEqual(segments.count, 1) + XCTAssertEqual(segments.reduce(0) { $0 + $1.units }, 1, accuracy: 1e-9) + XCTAssertEqual(segments[0].netUnits, 0.5, accuracy: 1e-9) + } + + func testSuspendDeliversNothingAndLaterRecordWins() { + let window = DateInterval(start: at(0), end: at(60)) + let schedule = [LoopHistoryMath.ScheduleValue(start: at(0), end: at(60), rate: 1.2)] + let deliveries = [ + LoopHistoryMath.BasalDelivery(start: at(0), end: at(60), rate: 3.0, kind: .temp, automatic: true), + LoopHistoryMath.BasalDelivery(start: at(20), end: at(40), rate: 0, kind: .suspended, automatic: false), + ] + let segments = LoopHistoryMath.basalSegments(window: window, schedule: schedule, deliveries: deliveries) + XCTAssertEqual(segments.map(\.kind), [.temp, .suspended, .temp]) + XCTAssertEqual(segments[1].units, 0) + XCTAssertEqual(segments[1].netUnits, -0.4, accuracy: 1e-9) + } + + func testNormalisedBasalPreservesDeliveredQuantityInPartialWindow() throws { + // The pump reports 1.05 U delivered, although the programmed rate implies 1.0625 U. + let dose = DoseEntry(type: .tempBasal, startDate: at(0), endDate: at(30), value: 2.125, + unit: .unitsPerHour, deliveredUnits: 1.05, automatic: true) + let delivery = try XCTUnwrap(LoopHistoryMath.BasalDelivery(dose: dose)) + for (end, expected) in [(30.0, 1.05), (15.0, 0.525)] { + let segments = LoopHistoryMath.basalSegments(window: DateInterval(start: at(0), end: at(end)), + schedule: [], deliveries: [delivery]) + XCTAssertEqual(segments.reduce(0) { $0 + $1.units }, expected, accuracy: 1e-9) + } + } + + func testHealthAndLocalPartitionsConserveBasalDelivery() throws { + let sample = HKQuantitySample(type: HKQuantityType(.insulinDelivery), + quantity: HKQuantity(unit: .internationalUnit(), doubleValue: 1), + start: at(0), end: at(60), + metadata: [HKMetadataKeyInsulinDeliveryReason: HKInsulinDeliveryReason.basal.rawValue]) + let left = try XCTUnwrap(BasalSegment(healthSample: sample, in: DateInterval(start: at(-30), end: at(30)))) + let right = try XCTUnwrap(BasalSegment(healthSample: sample, in: DateInterval(start: at(30), end: at(90)))) + XCTAssertEqual(left.units, 0.5, accuracy: 1e-9) + XCTAssertEqual(right.units, 0.5, accuracy: 1e-9, "Include basal beginning before the selected interval") + let dose = DoseEntry(type: .basal, startDate: at(0), endDate: at(60), value: 1, unit: .units, deliveredUnits: 1) + let local = LoopHistoryMath.basalSegments(window: DateInterval(start: at(30), end: at(90)), schedule: [], + deliveries: [try XCTUnwrap(LoopHistoryMath.BasalDelivery(dose: dose))]) + XCTAssertEqual(left.units + local.reduce(0) { $0 + $1.units }, 1, accuracy: 1e-9) + XCTAssertNil(BasalSegment(healthSample: sample, in: DateInterval(start: at(60), end: at(90)))) + + } + + func testBolusWindowIsHalfOpenAndPreservesDeliveredUnits() { + let window = DateInterval(start: at(0), end: at(60)) + for (minute, expected) in [(-1.0, false), (0.0, true), (30.0, true), (60.0, false)] { + let dose = DoseEntry(type: .bolus, startDate: at(minute), value: 1, unit: .units, deliveredUnits: 0.75) + let event = BolusEvent(dose: dose, in: window) + XCTAssertEqual(event != nil, expected, "Bolus at minute \(minute)") + if expected { XCTAssertEqual(event?.units, 0.75) } + } + } + + // MARK: Glucose + + func testTimeInRangeBandsAndRoundingSumTo100() { + let values: [Double] = [50, 60, 100, 100, 100, 200, 300] + let points = values.enumerated().map { GlucosePoint(date: at(Double($0.offset * 5)), mgdl: $0.element) } + let fractions = LoopHistoryMath.timeInRange(points) + XCTAssertEqual(fractions[.veryLow]!, 1 / 7, accuracy: 1e-9) + XCTAssertEqual(fractions[.low]!, 1 / 7, accuracy: 1e-9) + XCTAssertEqual(fractions[.inRange]!, 3 / 7, accuracy: 1e-9) + XCTAssertEqual(fractions[.high]!, 1 / 7, accuracy: 1e-9) + XCTAssertEqual(fractions[.veryHigh]!, 1 / 7, accuracy: 1e-9) + XCTAssertEqual(LoopHistoryMath.roundedPercentages(fractions).values.reduce(0, +), 100) + } + + func testBandEdgesFollowConsensusThresholds() { + XCTAssertEqual(LoopHistoryMath.RangeBand.band(for: 53.9), .veryLow) + XCTAssertEqual(LoopHistoryMath.RangeBand.band(for: 54), .low) + XCTAssertEqual(LoopHistoryMath.RangeBand.band(for: 70), .inRange) + XCTAssertEqual(LoopHistoryMath.RangeBand.band(for: 180), .inRange) + XCTAssertEqual(LoopHistoryMath.RangeBand.band(for: 181), .high) + XCTAssertEqual(LoopHistoryMath.RangeBand.band(for: 251), .veryHigh) + } + + func testGMIFromMean() { + let points = [GlucosePoint(date: at(0), mgdl: 150), GlucosePoint(date: at(5), mgdl: 150)] + let stats = LoopHistoryMath.glucoseStats(points)! + XCTAssertEqual(stats.gmiPercent, 3.31 + 0.02392 * 150, accuracy: 1e-9) + XCTAssertEqual(stats.gmiMmolMol, (stats.gmiPercent - 2.152) * 10.929, accuracy: 1e-9) + XCTAssertNil(LoopHistoryMath.glucoseStats([points[0]])) + } + + func testPercentileInterpolates() { + XCTAssertEqual(LoopHistoryMath.percentile([1, 2, 3, 4, 5], 0.5), 3) + XCTAssertEqual(LoopHistoryMath.percentile([1, 2, 3, 4], 0.5), 2.5) + XCTAssertEqual(LoopHistoryMath.percentile([10, 20], 0.25), 12.5) + } + + // MARK: Loop modes + + func testLoopModesStartAtFirstModeRecord() { + let interval = DateInterval(start: at(0), end: at(60)) + let runs = stride(from: 0.0, through: 60, by: 5).map { LoopHistoryMath.LoopRun(date: at($0), succeeded: true, error: nil) } + let spans = LoopHistoryMath.loopModeSpans(interval: interval, runs: runs, + modeChanges: [.init(date: at(30), closedLoop: true)], coverageStart: at(0)) + XCTAssertEqual(spans.first?.start, at(30), "Before the first record the mode is unknown and left out") + XCTAssertEqual(LoopHistoryMath.duration(of: .closed, in: spans), 30 * 60, accuracy: 1) + + XCTAssertTrue(LoopHistoryMath.loopModeSpans(interval: interval, runs: runs, modeChanges: [], coverageStart: at(0)).isEmpty) + } + + func testLoopModesClassifyOpenAndLimited() { + let interval = DateInterval(start: at(0), end: at(90)) + // Runs succeed until 20 min, then fail with an error, then stop. + var runs = stride(from: 0.0, through: 20, by: 5).map { LoopHistoryMath.LoopRun(date: at($0), succeeded: true, error: nil) } + runs.append(.init(date: at(25), succeeded: false, error: "Glucose too old")) + let changes: [LoopHistoryMath.ModeChange] = [.init(date: at(0), closedLoop: true), .init(date: at(60), closedLoop: false)] + + let spans = LoopHistoryMath.loopModeSpans(interval: interval, runs: runs, modeChanges: changes, coverageStart: at(0)) + XCTAssertEqual(spans.map(\.mode), [.closed, .limited, .open]) + XCTAssertEqual(spans[1].cause, "Glucose too old") + XCTAssertEqual(spans[1].start, at(35), "Limited starts once the last good run is over 15 minutes old") + XCTAssertEqual(spans[2].start, at(55), "The slot ending at the switch-off counts as open") + } + + // MARK: Calendar + + func testDaysAndQuarterMarksOnClockChangeDay() throws { + var calendar = Calendar(identifier: .gregorian) + calendar.timeZone = try XCTUnwrap(TimeZone(identifier: "Europe/London")) + // 25 Oct 2026: clocks go back an hour, so the day is 25 hours long. + let day = try XCTUnwrap(calendar.date(from: DateComponents(year: 2026, month: 10, day: 25))) + let next = try XCTUnwrap(calendar.date(byAdding: .day, value: 1, to: day)) + XCTAssertEqual(next.timeIntervalSince(day), 25 * 3600) + + let marks = DayAxis.quarterDayMarks(in: DateInterval(start: day, end: next), calendar: calendar) + XCTAssertEqual(marks.map { calendar.component(.hour, from: $0) }, [0, 6, 12, 18, 0]) + + let days = LoopHistoryMath.days(in: DateInterval(start: day, end: next.addingTimeInterval(3600)), calendar: calendar) + XCTAssertEqual(days.count, 2) + XCTAssertEqual(days[0].duration, 25 * 3600) + } + + func testWeeklyAveragesDays() { + let monday = Date(timeIntervalSinceReferenceDate: 815_270_400) // 9436 days after Monday 1 Jan 2001, so a Monday at midnight UTC + var calendar = Calendar(identifier: .gregorian) + calendar.timeZone = TimeZone(identifier: "UTC")! + let totals = (0..<14).map { LoopHistoryMath.DayTotal(day: monday.addingTimeInterval(Double($0) * 86400), basal: 10, bolus: Double($0)) } + let weeks = LoopHistoryMath.weekly(totals, calendar: calendar) + XCTAssertEqual(weeks.count, 2) + XCTAssertEqual(weeks[0].bolus, 3, accuracy: 1e-9) + XCTAssertEqual(weeks[1].bolus, 10, accuracy: 1e-9) + } + + func testDailyInsulinAverageLeavesOutTheDayInProgress() { + let day0 = Date(timeIntervalSinceReferenceDate: 815_270_400) + let complete = (0..<3).map { LoopHistoryMath.DayTotal(day: day0.addingTimeInterval(Double($0) * 86400), basal: 10, bolus: 20) } + let today = LoopHistoryMath.DayTotal(day: day0.addingTimeInterval(3 * 86400), basal: 3, bolus: 2, isComplete: false) + XCTAssertEqual(LoopHistoryMath.averageDailyInsulin(complete + [today]), 30, accuracy: 1e-9) + XCTAssertEqual(LoopHistoryMath.averagingDays(complete + [today]).count, 3) + // With nothing complete, the day in progress is all there is to show. + XCTAssertEqual(LoopHistoryMath.averageDailyInsulin([today]), 5, accuracy: 1e-9) + } + + func testGapMessageForADayWithoutReadings() { + let start = Date(timeIntervalSinceReferenceDate: 815_270_400) + let day = DateInterval(start: start, duration: 86400) + let empty = DayAxis.gaps(in: [], window: day, until: day.end.addingTimeInterval(3600)) + XCTAssertEqual(DayAxis.gapMessage(empty, window: day, until: day.end.addingTimeInterval(3600)), "No CGM data on this day") + let morning = start.addingTimeInterval(9 * 3600) + XCTAssertEqual(DayAxis.gapMessage(DayAxis.gaps(in: [], window: day, until: morning), window: day, until: morning), "No CGM data yet today") + let reading = [GlucosePoint(date: start.addingTimeInterval(12 * 3600), mgdl: 120)] + let partial = DayAxis.gaps(in: reading, window: day, until: day.end) + XCTAssertTrue(DayAxis.gapMessage(partial, window: day, until: day.end)?.hasSuffix("and 1 shorter gap") ?? false) + } + + // MARK: Formatting + + func testRangeFormatting() throws { + let calendar = Calendar.current + let a = try XCTUnwrap(calendar.date(from: DateComponents(year: 2026, month: 10, day: 12, hour: 12))) + let b = try XCTUnwrap(calendar.date(from: DateComponents(year: 2026, month: 10, day: 25, hour: 12))) + let c = try XCTUnwrap(calendar.date(from: DateComponents(year: 2026, month: 9, day: 28, hour: 12))) + // Ranges and durations come from the system's formatters, so they follow the user's locale; + // the test host runs in en_US. + XCTAssertEqual(LoopFormat.range(b, b), LoopFormat.day(b)) + let sameMonth = LoopFormat.range(a, b) + XCTAssertTrue(sameMonth.contains("12") && sameMonth.contains("25")) + XCTAssertEqual(sameMonth.components(separatedBy: "2026").count, 2, "the year appears once") + let twoMonths = LoopFormat.range(c, b) + XCTAssertTrue(twoMonths.contains("Sep") && twoMonths.contains("Oct")) + XCTAssertEqual(LoopFormat.duration(13 * 86400 + 11 * 3600), "13d 11h") + XCTAssertEqual(LoopFormat.duration(9 * 3600 + 45 * 60), "9h 45m") + XCTAssertEqual(LoopFormat.number(7.25, decimals: 1), 7.25.formatted(.number.precision(.fractionLength(1)).grouping(.never))) + XCTAssertEqual(LoopFormat.signed(-0.4), "−0.40") + XCTAssertEqual(LoopFormat.signed(0.0001), "+0.00") + } + + @MainActor + func testCSVExportsEightColumnsWithASCIINumbers() throws { + let day = Calendar.current.startOfDay(for: start) + for isMmol in [true, false] { + var summary = TrendsModel.Summary(interval: DateInterval(start: day, duration: 86400), + unit: GlucoseUnitStyle(isMmol: isMmol)) + summary.glucose = [GlucosePoint(date: day, mgdl: 131.53286)] + summary.totals = [.init(day: day, basal: 1.25, bolus: 2.5)] + summary.carbsByDay = [day: 45] + let url = try TrendsModel.exportCSV(summary) + defer { try? FileManager.default.removeItem(at: url) } + let rows = try String(contentsOf: url, encoding: .utf8).components(separatedBy: "\n") + XCTAssertEqual(rows.count, 2) + XCTAssertEqual(rows[0].components(separatedBy: ",").count, 8) + let columns = rows[1].components(separatedBy: ",") + XCTAssertEqual(columns.count, 8) + XCTAssertEqual(Array(columns.dropFirst()), [isMmol ? "7.3" : "132", "1", "100", "1.25", "2.50", "3.75", "45"]) + } + } + + func testModeHistoryRetainsTheModeBeforeTheRetentionWindow() throws { + let suite = "LoopHistoryMathTests-\(UUID().uuidString)" + let defaults = try XCTUnwrap(UserDefaults(suiteName: suite)) + defer { defaults.removePersistentDomain(forName: suite) } + let history = LoopModeHistory(defaults: defaults) + history.record(closedLoop: false, at: at(0)) + history.record(closedLoop: true, at: at(60)) + let switchDate = at(200 * 1440) + history.record(closedLoop: false, at: switchDate) + XCTAssertEqual(history.changes, [.init(date: at(60), closedLoop: true), .init(date: switchDate, closedLoop: false)]) + let interval = DateInterval(start: switchDate.addingTimeInterval(-3600), end: switchDate) + let spans = LoopHistoryMath.loopModeSpans(interval: interval, runs: [], modeChanges: history.changes, + coverageStart: interval.start) + XCTAssertEqual(spans.first?.start, interval.start, "Retaining the old mode must preserve recent coverage") + } + + func testIssueDescriptions() { + XCTAssertEqual(LoopHistoryProvider.describe(issue: "glucoseTooOld"), "Glucose too old") + XCTAssertEqual(LoopHistoryProvider.describe(issue: "pumpDataTooOld"), "Pump data too old") + } +}