├── .clang-format-ci ├── .gitignore ├── .kokoro ├── .travis.yml ├── BUILD ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Examples ├── Flags.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Flags │ ├── Default-568h@2x.png │ ├── Flags.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── Flags.xcscheme │ │ └── FlagsUITests.xcscheme │ ├── FlagsUITests │ ├── FlagsUITests.m │ └── Info.plist │ └── MDFInternationalizationExample │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── AppIcon │ ├── appicon-20@2x.png │ ├── appicon-20@3x.png │ ├── appicon-29@2x.png │ ├── appicon-29@3x.png │ ├── appicon-40@2x.png │ ├── appicon-40@3x.png │ ├── appicon-60@2x.png │ └── appicon-60@3x.png │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon-1024.png │ │ ├── Contents.json │ │ ├── appicon-20@2x.png │ │ ├── appicon-20@3x.png │ │ ├── appicon-29@2x.png │ │ ├── appicon-29@3x.png │ │ ├── appicon-40@2x.png │ │ ├── appicon-40@3x.png │ │ ├── appicon-60@2x.png │ │ └── appicon-60@3x.png │ ├── BidiIcon.imageset │ │ ├── Contents.json │ │ ├── baseline_compare_arrows_black_36pt_1x.png │ │ ├── baseline_compare_arrows_black_36pt_2x.png │ │ └── baseline_compare_arrows_black_36pt_3x.png │ ├── BigAppIcon.imageset │ │ ├── BigAppIcon.png │ │ └── Contents.json │ ├── Contents.json │ ├── FlagIcon.imageset │ │ ├── Contents.json │ │ ├── ic_flag_36pt.png │ │ ├── ic_flag_36pt_2x.png │ │ └── ic_flag_36pt_3x.png │ ├── InfoIcon.imageset │ │ ├── Contents.json │ │ ├── ic_info_36pt.png │ │ ├── ic_info_36pt_2x.png │ │ └── ic_info_36pt_3x.png │ ├── Nonspeaking.imageset │ │ ├── Contents.json │ │ ├── ic_hearing_white_48pt.png │ │ ├── ic_hearing_white_48pt_2x.png │ │ └── ic_hearing_white_48pt_3x.png │ ├── Speaking.imageset │ │ ├── Contents.json │ │ ├── ic_hearing_48pt.png │ │ ├── ic_hearing_48pt_2x.png │ │ └── ic_hearing_48pt_3x.png │ └── Standard.imageset │ │ ├── Contents.json │ │ └── LtoR.png │ ├── Attic │ ├── ARG.png │ ├── AUS.png │ ├── AppIcon-1024.png │ ├── BTN.png │ ├── BigAppIcon.png │ ├── CAN.png │ ├── FRA.png │ ├── Flag_of_Argentina.svg │ ├── Flag_of_Australia_(converted).svg │ ├── Flag_of_Bhutan.svg │ ├── Flag_of_Canada.svg │ ├── Flag_of_France.svg │ ├── Flag_of_Greece.svg │ ├── Flag_of_India.svg │ ├── Flag_of_Jamaica.svg │ ├── Flag_of_Japan.svg │ ├── Flag_of_Mexico.svg │ ├── Flag_of_Nepal.svg │ ├── Flag_of_Papua_New_Guinea.svg │ ├── Flag_of_Qatar.svg │ ├── Flag_of_Slovakia.svg │ ├── Flag_of_South_Africa.svg │ ├── Flag_of_Tunisia.svg │ ├── Flag_of_Zambia.svg │ ├── Flag_of_the_United_States.svg │ ├── GRC.png │ ├── IND.png │ ├── JAM.png │ ├── JPN.png │ ├── MEX.png │ ├── NPL.png │ ├── PNG.png │ ├── QAT.png │ ├── SVK.png │ ├── TUN.png │ ├── USA.png │ ├── ZAF.png │ ├── ZMB.png │ ├── ic_flag_black_1024.png │ ├── ic_flag_black_48px.svg │ ├── ic_hearing_black_48dp │ │ ├── ic_hearing_48pt.png │ │ ├── ic_hearing_48pt_2x.png │ │ └── ic_hearing_48pt_3x.png │ ├── ic_hearing_black_48px.svg │ └── ic_hearing_grey_48dp │ │ ├── ic_hearing_grey_48pt.png │ │ ├── ic_hearing_grey_48pt_2x.png │ │ └── ic_hearing_grey_48pt_3x.png │ ├── Base.lproj │ ├── Countries.strings │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── BidirectionalViewController.h │ ├── BidirectionalViewController.m │ ├── CountryCell.h │ ├── CountryCell.m │ ├── CountryTableViewController.h │ ├── CountryTableViewController.m │ ├── Flags.xcassets │ ├── ARG.imageset │ │ ├── ARG.png │ │ └── Contents.json │ ├── AUS.imageset │ │ ├── AUS.png │ │ └── Contents.json │ ├── BTN.imageset │ │ ├── BTN.png │ │ └── Contents.json │ ├── CAN.imageset │ │ ├── CAN.png │ │ └── Contents.json │ ├── Contents.json │ ├── FRA.imageset │ │ ├── Contents.json │ │ └── FRA.png │ ├── GRC.imageset │ │ ├── Contents.json │ │ └── GRC.png │ ├── IND.imageset │ │ ├── Contents.json │ │ └── IND.png │ ├── JAM.imageset │ │ ├── Contents.json │ │ └── JAM.png │ ├── JPN.imageset │ │ ├── Contents.json │ │ └── JPN.png │ ├── MEX.imageset │ │ ├── Contents.json │ │ └── MEX.png │ ├── NPL.imageset │ │ ├── Contents.json │ │ └── NPL.png │ ├── PNG.imageset │ │ ├── Contents.json │ │ └── PNG.png │ ├── QAT.imageset │ │ ├── Contents.json │ │ └── QAT.png │ ├── SVK.imageset │ │ ├── Contents.json │ │ └── SVK.png │ ├── TUN.imageset │ │ ├── Contents.json │ │ └── TUN.png │ ├── USA.imageset │ │ ├── Contents.json │ │ └── USA.png │ ├── ZAF.imageset │ │ ├── Contents.json │ │ └── ZAF.png │ └── ZMB.imageset │ │ ├── Contents.json │ │ └── ZMB.png │ ├── Info.plist │ ├── InformationViewController.h │ ├── InformationViewController.m │ ├── ar.lproj │ ├── Countries.strings │ ├── InfoPlist.strings │ └── Main.strings │ ├── en.lproj │ ├── Countries.strings │ ├── Info.plist │ ├── InfoPlist.strings │ └── Main.strings │ └── main.m ├── LICENSE ├── MDFInternationalization.podspec ├── MDFInternationalization.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ ├── MDFInternationalization.xcscheme │ │ └── MDFInternationalizationTests.xcscheme └── xcuserdata │ └── iangordon.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── README.md ├── Sources ├── Info.plist ├── MDFInternationalization.h ├── MDFRTL.h ├── MDFRTL.m ├── NSLocale+MaterialRTL.h ├── NSLocale+MaterialRTL.m ├── NSString+MaterialBidi.h ├── NSString+MaterialBidi.m ├── UIImage+MaterialRTL.h ├── UIImage+MaterialRTL.m ├── UIView+MaterialRTL.h └── UIView+MaterialRTL.m ├── Tests ├── Info.plist ├── MDFBidiTests.m ├── MDFInternationalizationTests.m └── MDFRTLTests.m ├── WORKSPACE └── apple_framework_relative_headers.bzl /.clang-format-ci: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2018-present The Material Foundation Authors. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | REPO="material-foundation/material-internationalization-ios" 21 | 22 | # The tagged version of https://github.com/material-foundation/clang-format-ci to check out. 23 | # A * wildcard can be used to check out the latest release of a given version. 24 | CLANG_FORMAT_CI_VERSION="v1.*" 25 | 26 | CLANG_FORMAT_CI_SRC_DIR=".clang-format-ci-src" 27 | 28 | # Will run git clang-format on the branch's changes, reporting a failure if the linter generated any 29 | # stylistic changes. 30 | # 31 | # For local runs, you must set the following environment variables: 32 | # 33 | # GITHUB_API_TOKEN -> Create a token here: https://github.com/settings/tokens. 34 | # Must have public_repo scope. 35 | # KOKORO_GITHUB_PULL_REQUEST_NUMBER="###" -> The PR # you want to post the API diff results to. 36 | # KOKORO_GITHUB_PULL_REQUEST_COMMIT="..." -> The PR commit you want to post to. 37 | # 38 | # And install the following tools: 39 | # 40 | # - clang-format 41 | # - git-clang-format 42 | lint_clang_format() { 43 | if [ ! -d "$CLANG_FORMAT_CI_SRC_DIR" ]; then 44 | git clone --recurse-submodules https://github.com/material-foundation/clang-format-ci.git "$CLANG_FORMAT_CI_SRC_DIR" 45 | fi 46 | 47 | pushd "$CLANG_FORMAT_CI_SRC_DIR" 48 | git fetch > /dev/null 49 | TAG=$(git tag --sort=v:refname -l "$CLANG_FORMAT_CI_VERSION" | tail -n1) 50 | git checkout "$TAG" > /dev/null 51 | git submodule update --init --recursive 52 | echo "Using clang-format-ci $TAG" 53 | popd 54 | 55 | .clang-format-ci-src/from-kokoro.sh "$REPO" 56 | } 57 | 58 | lint_clang_format 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | .kokoro-ios-runner 3 | .clang-format-ci-src 4 | 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | # OS X System files 10 | .DS_Store 11 | 12 | ## Build generated 13 | build/ 14 | DerivedData/ 15 | 16 | ## Various settings 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | xcuserdata/ 26 | 27 | ## Other 28 | *.moved-aside 29 | *.xcuserstate 30 | 31 | ## Obj-C/Swift specific 32 | *.hmap 33 | *.ipa 34 | *.dSYM.zip 35 | *.dSYM 36 | 37 | # CocoaPods 38 | # 39 | # We recommend against adding the Pods directory to your .gitignore. However 40 | # you should judge for yourself, the pros and cons are mentioned at: 41 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 42 | # 43 | Pods/ 44 | 45 | # Carthage 46 | # 47 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 48 | # Carthage/Checkouts 49 | 50 | Carthage/Build 51 | 52 | # fastlane 53 | # 54 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 55 | # screenshots whenever they are needed. 56 | # For more information about the recommended setup visit: 57 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 58 | 59 | fastlane/report.xml 60 | fastlane/screenshots 61 | 62 | # Code Injection 63 | # 64 | # After new code Injection tools there's a generated folder /iOSInjectionProject 65 | # https://github.com/johnno1962/injectionforxcode 66 | 67 | iOSInjectionProject/ -------------------------------------------------------------------------------- /.kokoro: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2017-present The Material Foundation Authors. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands to stderr. 21 | set -x 22 | 23 | KOKORO_RUNNER_VERSION="v3.*" 24 | 25 | if [ ! -d .kokoro-ios-runner ]; then 26 | git clone https://github.com/material-foundation/kokoro-ios-runner.git .kokoro-ios-runner 27 | fi 28 | 29 | pushd .kokoro-ios-runner 30 | git fetch > /dev/null 31 | TAG=$(git tag --sort=v:refname -l "$KOKORO_RUNNER_VERSION" | tail -n1) 32 | git checkout "$TAG" > /dev/null 33 | popd 34 | 35 | if [ -n "$KOKORO_BUILD_NUMBER" ]; then 36 | bazel version 37 | use_bazel.sh 1.1.0 38 | bazel version 39 | fi 40 | 41 | ./.kokoro-ios-runner/bazel.sh test //:UnitTests --min-xcode-version 9.0 42 | 43 | echo "Success!" 44 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | sudo: false 3 | 4 | # Only do a shallow clone of our Git repo. 5 | # https://docs.travis-ci.com/user/customizing-the-build#Git-Clone-Depth 6 | git: 7 | depth: 3 8 | 9 | # Only fire off builds for specific branches. 10 | branches: 11 | only: 12 | - develop 13 | - stable 14 | - /^feature-.*$/ 15 | - release-candidate 16 | 17 | xcode_project: MDFInternationalization.xcodeproj 18 | xcode_scheme: MDFInternationalizationTests 19 | 20 | matrix: 21 | include: 22 | - osx_image: xcode9 23 | # The iPhone X was chosen because it is a device with a strange screen size and 24 | # the 'notch'. 25 | # OS 11.0 was chosen as the latest generally available iOS version. 26 | env: DESTINATION="platform=iOS Simulator,name=iPhone X,OS=11.0" SDK="iphonesimulator11.0" 27 | - osx_image: xcode9 28 | # The iPhone 7 Plus was chosen because it is a device with a 3x screen and also changes 29 | # its size category trait on rotation. 30 | # OS 10.3.1 was chosen to represent iOS 10. 31 | env: DESTINATION="platform=iOS Simulator,name=iPhone 7 Plus,OS=10.3.1" SDK="iphonesimulator11.0" 32 | - osx_image: xcode8.3 33 | # The iPad Pro 12.9 was chosen because it is the largest resolution we can test on. 34 | # OS 9.3 was chosen to round out the range of iOS versions we are testing on. 35 | env: DESTINATION="platform=iOS Simulator,name=iPad Pro (12.9-inch),OS=9.3" SDK="iphonesimulator10.3" 36 | - osx_image: xcode8.3 37 | # The iPhone 5 was chosen because it is a 32-bit device. 38 | # OS 8.1 was chosen because it is the earliest iOS offered here. 39 | env: DESTINATION="platform=iOS Simulator,name=iPhone 5,OS=8.1" SDK="iphonesimulator10.3" 40 | 41 | # Test Execution 42 | # TODO Enable set -euo pipefail 43 | script: 44 | - env 45 | - set -o pipefail 46 | - echo xcodebuild -project "$TRAVIS_XCODE_PROJECT" -scheme "$TRAVIS_XCODE_SCHEME" -sdk "$SDK" -destination "$DESTINATION" test 47 | - xcodebuild -project "$TRAVIS_XCODE_PROJECT" -scheme "$TRAVIS_XCODE_SCHEME" -sdk "$SDK" -destination "$DESTINATION" test | xcpretty -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2017-present The Material Foundation Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 16 | load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test_suite") 17 | load("@build_bazel_rules_apple//apple/testing/default_runner:ios_test_runner.bzl", "ios_test_runner") 18 | load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") 19 | load("@bazel_ios_warnings//:strict_warnings_objc_library.bzl", "strict_warnings_objc_library") 20 | load(":apple_framework_relative_headers.bzl", "apple_framework_relative_headers") 21 | 22 | licenses(["notice"]) # Apache 2.0 23 | 24 | exports_files(["LICENSE"]) 25 | 26 | strict_warnings_objc_library( 27 | name = "MDFInternationalization", 28 | srcs = glob([ 29 | "Sources/*.m", 30 | ]), 31 | hdrs = glob([ 32 | "Sources/*.h", 33 | ]), 34 | sdk_frameworks = [ 35 | "UIKit", 36 | "CoreGraphics", 37 | "CoreImage", 38 | ], 39 | enable_modules = 1, 40 | includes = ["Sources"], 41 | visibility = ["//visibility:public"], 42 | deps = [ 43 | ":MDFInternationalizationFrameworkHeaders", 44 | ], 45 | ) 46 | 47 | apple_framework_relative_headers( 48 | name = "MDFInternationalizationFrameworkHeaders", 49 | hdrs = glob([ 50 | "Sources/*.h", 51 | ]), 52 | framework_name = "MDFInternationalization", 53 | ) 54 | 55 | build_test( 56 | name = "BuildTest", 57 | targets = [ 58 | ":MDFInternationalization" 59 | ], 60 | ) 61 | 62 | objc_library( 63 | name = "UnitTestsLib", 64 | srcs = glob([ 65 | "Tests/*.m", 66 | ]), 67 | deps = [ 68 | ":MDFInternationalization", 69 | ":MDFInternationalizationFrameworkHeaders", 70 | ], 71 | ) 72 | 73 | ios_test_runner( 74 | name = "IPAD_PRO_12_9_IN_9_3", 75 | device_type = "iPad Pro (12.9-inch)", 76 | os_version = "9.3", 77 | ) 78 | 79 | ios_test_runner( 80 | name = "IPHONE_7_PLUS_IN_10_3", 81 | device_type = "iPhone 7 Plus", 82 | os_version = "10.3", 83 | ) 84 | 85 | ios_test_runner( 86 | name = "IPHONE_X_IN_11_4", 87 | device_type = "iPhone X", 88 | os_version = "11.4", 89 | ) 90 | 91 | ios_test_runner( 92 | name = "IPHONE_XS_MAX_IN_12_2", 93 | device_type = "iPhone Xs Max", 94 | os_version = "12.2", 95 | ) 96 | 97 | ios_unit_test_suite( 98 | name = "UnitTests", 99 | deps = [ 100 | ":UnitTestsLib", 101 | ], 102 | minimum_os_version = "9.0", 103 | timeout = "short", 104 | runners = [ 105 | ":IPAD_PRO_12_9_IN_9_3", 106 | ":IPHONE_7_PLUS_IN_10_3", 107 | ":IPHONE_X_IN_11_4", 108 | ":IPHONE_XS_MAX_IN_12_2", 109 | ], 110 | ) 111 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 3.0.0 2 | 3 | This major release drops support for iOS 9 and 10. 4 | 5 | # 2.0.1 6 | 7 | This patch release fixes framework-style imports when using bazel to build this library as an 8 | external dependency. 9 | 10 | ## Non-source changes 11 | 12 | * [Add workspace_root to framework import path. (#51)](https://github.com/material-foundation/material-internationalization-ios/commit/25a16214c9ca8ecfbb89f4168f7967c3a0549921) (featherless) 13 | 14 | # 2.0.0 15 | 16 | This major release upgrades the bazel dependencies and workspace. This change is breaking for anyone 17 | using bazel to build this library. In order to use this library with bazel, you will also need to 18 | upgrade your workspace versions to match the ones now used in this library's `WORKSPACE` file. 19 | 20 | * [Update bazel workspace to latest versions. (#49)](https://github.com/material-foundation/material-internationalization-ios/commit/2ff10388f4a61c16a856092cdfba709ddbcdd2eb) (featherless) 21 | 22 | # 1.1.1 23 | 24 | * [Add MDFInternationalizationFrameworkHeaders as a dependency for bazel. (#47)](https://github.com/material-foundation/material-internationalization-ios/commit/580082c633f1e1146fd0634f02dcf39270c5375a) (featherless) 25 | * [Integrate clang-format-ci. (#45)](https://github.com/material-foundation/material-internationalization-ios/commit/3ec6a305948a1bdac426e10811afbec691065341) (featherless) 26 | * [Update to latest Xcode](https://github.com/material-foundation/material-internationalization-ios/commit/eb2107d3208f045d6464115f3cb5453d06a9c243) (Ian Gordon) 27 | * [Update README.md](https://github.com/material-foundation/material-internationalization-ios/commit/39955811b952cc7a2f37201faeb38eeb3a239636) (ianegordon) 28 | 29 | # 1.1.0 30 | 31 | * [Add Bidi utilities (#42)](https://github.com/material-foundation/material-internationalization-ios/pull/42) (Ian Gordon) 32 | * [Add support for relative paths to the Bazel build](https://github.com/material-foundation/material-internationalization-ios/pull/41) (Ian Gordon) 33 | * [Bazel specific import paths are no longer required.](https://github.com/material-foundation/material-internationalization-ios/pull/38) (dmaclach) 34 | * [Silence warnings (#37)](https://github.com/material-foundation/material-internationalization-ios/pull/37) (Ian Gordon) 35 | 36 | # 1.0.4 37 | 38 | * [[Bazel] Fix BUILD file SDK dependencies (#36)](https://github.com/material-components/material-components-ios/commit/298b51d3523a346a404e7e8c8bda14e27ed65226) (Robert Moore) 39 | 40 | # 1.0.3 41 | 42 | * [Add compile time flag for import style (#34)](https://github.com/material-foundation/material-internationalization-ios/88af44b587cb03408a827b97aa82234f6a7abc23) (ianegordon) 43 | * [Add C++ guards so the compiler does not mangle symbol names. (#31)](https://github.com/material-foundation/material-internationalization-ios/5060976bcf45947d1176f8e060d13d4447b60a10) (Adrian Secord) 44 | * [Remove framework-style headers from the umbrella header. (#30)](https://github.com/material-foundation/material-internationalization-ios/fef1a31313a4a8aa0234cce416e1615c7054cf9d) (featherless) 45 | * [Add support for bazel and kokoro. (#27)](https://github.com/material-foundation/material-internationalization-ios/42a9bdf739a8de112fbcf8d395640f3477306fae) (featherless) 46 | * [Silence NSNumber to BOOL conversion analyzer warning (#28)](https://github.com/material-foundation/material-internationalization-ios/5630a566396477ce6df5fd48b885aefdf40826d6) (ianegordon) 47 | * [[RTL] Comment corrections and clarifications. (#26)](https://github.com/material-foundation/material-internationalization-ios/b6d5bfb53cac16de15c75d6571da5e15cdea4884) (Will Larche) 48 | 49 | # 1.0.2 50 | 51 | * [Update Project and Scheme to latest recommended settings](https://github.com/material-foundation/material-internationalization-ios/8a0317501403463fab8c1d541eddf0f649df2fc6) (Ian Gordon) 52 | * [Update Travis-CI build environments and simulators (#24)](https://github.com/material-foundation/material-internationalization-ios/25521a9733fea64a2c9cde737d1037d2ec5eee74) (ianegordon) 53 | * [Disable warnings added in Xcode 9 (#23)](https://github.com/material-foundation/material-internationalization-ios/6909be2fcde579116d7e454ae308dac777b740bb) (ianegordon) 54 | 55 | # 1.0.1 56 | 57 | * [Modify sharedApplication call to avoid extension error (#17)](https://github.com/material-foundation/material-internationalization-ios/commit/902e392e78c11e8ae5169135dd7a0077bcf37d48) (ianegordon) 58 | 59 | # 1.0.0 60 | 61 | Initial release. 62 | 63 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | * @ianegordon 5 | * @arcank 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mdc-coc@googlegroups.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the [small print](#the-small-print)). 2 | 3 | ### Before you contribute 4 | 5 | Before we can use your code, you must sign the 6 | [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) 7 | (CLA), which you can do online. The CLA is necessary mainly because you own the copyright to your 8 | changes, even after your contribution becomes part of our codebase, so we need your permission to 9 | use and distribute your code. We also need to be sure of various other things—for instance that 10 | you'll tell us if you know that your code infringes on other people's patents. You don't have to 11 | sign the CLA until after you've submitted your code for review and a member has approved it, but you 12 | must do it before we can put your code into our codebase. Before you start working on a larger 13 | contribution, you should get in touch with us first through the issue tracker with your idea so that 14 | we can help out and possibly guide you. Coordinating up front makes it much easier to avoid 15 | frustration later on. 16 | 17 | ### Code reviews 18 | 19 | All submissions, including submissions by project members, require review. We use Github pull 20 | requests for this purpose. 21 | 22 | ### The small print 23 | 24 | Contributions made by corporations are covered by a different agreement than the one above, the 25 | [Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). 26 | 27 | -------------------------------------------------------------------------------- /Examples/Flags.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/Flags.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Flags.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Examples/Flags/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/Default-568h@2x.png -------------------------------------------------------------------------------- /Examples/Flags/Flags.xcodeproj/xcshareddata/xcschemes/Flags.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Examples/Flags/Flags.xcodeproj/xcshareddata/xcschemes/FlagsUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 48 | 49 | 50 | 51 | 57 | 58 | 60 | 61 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Examples/Flags/FlagsUITests/FlagsUITests.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface FlagsUITests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation FlagsUITests 24 | 25 | - (void)setUp { 26 | [super setUp]; 27 | 28 | // Put setup code here. This method is called before the invocation of each test method in the class. 29 | 30 | // In UI tests it is usually best to stop immediately when a failure occurs. 31 | self.continueAfterFailure = NO; 32 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 33 | [[[XCUIApplication alloc] init] launch]; 34 | 35 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 36 | } 37 | 38 | - (void)tearDown { 39 | // Put teardown code here. This method is called after the invocation of each test method in the class. 40 | [super tearDown]; 41 | } 42 | 43 | - (void)testAppStartup { 44 | // Use recording to get started writing UI tests. 45 | // Use XCTAssert and related functions to verify your tests produce the correct results. 46 | } 47 | 48 | - (void)testSimpleNavigation { 49 | // Use recording to get started writing UI tests. 50 | // Use XCTAssert and related functions to verify your tests produce the correct results. 51 | 52 | XCUIApplication *app = [[XCUIApplication alloc] init]; 53 | XCUIElementQuery *tablesQuery = app.tables; 54 | [tablesQuery.staticTexts[@"Japan"] tap]; 55 | 56 | XCUIElementQuery *tabBarsQuery = app.tabBars; 57 | [tabBarsQuery.buttons[@"Info"] tap]; 58 | [tabBarsQuery.buttons[@"Flags"] tap]; 59 | [tablesQuery.staticTexts[@"Mexico"] swipeUp]; 60 | [tablesQuery.staticTexts[@"United States of America"] tap]; 61 | [tablesQuery.staticTexts[@"Slovakia"] tap]; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Examples/Flags/FlagsUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface AppDelegate : UIResponder 20 | 21 | @property (strong, nonatomic) UIWindow *window; 22 | 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "AppDelegate.h" 18 | 19 | #import "CountryTableViewController.h" 20 | 21 | @interface AppDelegate () 22 | 23 | @end 24 | 25 | @implementation AppDelegate 26 | 27 | - (BOOL)application:(UIApplication *)application 28 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 29 | // Allow playback so country names can be spoken over the main speaker 30 | NSError *error; 31 | [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]; 32 | if (error) { 33 | NSLog(@"Error setting the category on AVAudioSession"); 34 | } 35 | 36 | return YES; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-20@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-20@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-29@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-29@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-40@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-40@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-60@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/AppIcon/appicon-60@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "appicon-20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "appicon-20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "appicon-29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "appicon-29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "appicon-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "appicon-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "appicon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "appicon-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "1024x1024", 53 | "idiom" : "ios-marketing", 54 | "filename" : "AppIcon-1024.png", 55 | "scale" : "1x" 56 | } 57 | ], 58 | "info" : { 59 | "version" : 1, 60 | "author" : "xcode" 61 | } 62 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-20@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-20@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-29@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-29@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-40@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-40@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-60@2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/AppIcon.appiconset/appicon-60@3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "baseline_compare_arrows_black_36pt_1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "baseline_compare_arrows_black_36pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "baseline_compare_arrows_black_36pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/baseline_compare_arrows_black_36pt_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/baseline_compare_arrows_black_36pt_1x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/baseline_compare_arrows_black_36pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/baseline_compare_arrows_black_36pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/baseline_compare_arrows_black_36pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BidiIcon.imageset/baseline_compare_arrows_black_36pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BigAppIcon.imageset/BigAppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BigAppIcon.imageset/BigAppIcon.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/BigAppIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "BigAppIcon.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_flag_36pt.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "ic_flag_36pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "ic_flag_36pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/ic_flag_36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/ic_flag_36pt.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/ic_flag_36pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/ic_flag_36pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/ic_flag_36pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/FlagIcon.imageset/ic_flag_36pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_info_36pt.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "ic_info_36pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "ic_info_36pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/ic_info_36pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/ic_info_36pt.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/ic_info_36pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/ic_info_36pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/ic_info_36pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/InfoIcon.imageset/ic_info_36pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_hearing_white_48pt.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "ic_hearing_white_48pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "ic_hearing_white_48pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/ic_hearing_white_48pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/ic_hearing_white_48pt.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/ic_hearing_white_48pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/ic_hearing_white_48pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/ic_hearing_white_48pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Nonspeaking.imageset/ic_hearing_white_48pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_hearing_48pt.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "ic_hearing_48pt_2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "ic_hearing_48pt_3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/ic_hearing_48pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/ic_hearing_48pt.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/ic_hearing_48pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/ic_hearing_48pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/ic_hearing_48pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Speaking.imageset/ic_hearing_48pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Standard.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LtoR.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Standard.imageset/LtoR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Assets.xcassets/Standard.imageset/LtoR.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ARG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ARG.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/AUS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/AUS.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/AppIcon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/AppIcon-1024.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/BTN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/BTN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/BigAppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/BigAppIcon.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/CAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/CAN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/FRA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/FRA.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Argentina.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Australia_(converted).svg: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Canada.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_France.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Greece.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_India.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Jamaica.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Japan.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Nepal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flag of Nepal 4 | Coding according to the official construction in "Constitution of the Kingdom of Nepal, Article 5, Shedule 1", adopted in November 1990 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Papua_New_Guinea.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flag of Papua New Guinea 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Qatar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Slovakia.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flag of Slovakia 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_South_Africa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_Tunisia.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/Flag_of_the_United_States.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/GRC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/GRC.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/IND.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/IND.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/JAM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/JAM.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/JPN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/JPN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/MEX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/MEX.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/NPL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/NPL.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/PNG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/PNG.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/QAT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/QAT.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/SVK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/SVK.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/TUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/TUN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/USA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/USA.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ZAF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ZAF.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ZMB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ZMB.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_flag_black_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_flag_black_1024.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_flag_black_48px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48dp/ic_hearing_48pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48dp/ic_hearing_48pt.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48dp/ic_hearing_48pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48dp/ic_hearing_48pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48dp/ic_hearing_48pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48dp/ic_hearing_48pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_black_48px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_grey_48dp/ic_hearing_grey_48pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_grey_48dp/ic_hearing_grey_48pt.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_grey_48dp/ic_hearing_grey_48pt_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_grey_48dp/ic_hearing_grey_48pt_2x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_grey_48dp/ic_hearing_grey_48pt_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Attic/ic_hearing_grey_48dp/ic_hearing_grey_48pt_3x.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Base.lproj/Countries.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Countries.strings 3 | MDFInternationalizationExample 4 | 5 | Created by Ian Gordon on 9/8/16. 6 | Copyright © 2016 Google. All rights reserved. 7 | */ 8 | 9 | "ARG" = "Argentina"; 10 | "AUS" = "Australia"; 11 | "BTN" = "Bhutan"; 12 | "CAN" = "Canada"; 13 | "FRA" = "France"; 14 | "GRC" = "Greece"; 15 | "IND" = "India"; 16 | "JAM" = "Jamaica"; 17 | "JPN" = "Japan"; 18 | "MEX" = "Mexico"; 19 | "NPL" = "Nepal"; 20 | "PNG" = "Papua New Guinea"; 21 | "QAT" = "Qatar"; 22 | "SVK" = "Slovakia"; 23 | "TUN" = "Tunisia"; 24 | "USA" = "United States of America"; 25 | "ZAF" = "South Africa"; 26 | "ZMB" = "Zambia"; 27 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/BidirectionalViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface BidirectionalViewController : UIViewController 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/BidirectionalViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "BidirectionalViewController.h" 18 | 19 | #import "MDFInternationalization.h" 20 | 21 | 22 | static NSString *LTREmbedding = @"\u202a"; // left-to-right embedding 23 | static NSString *RTLEmbedding = @"\u202b"; // right-to-left embedding 24 | static NSString *BidiPopEmbedding = @"\u202c"; // pop directional embedding 25 | 26 | static NSString *LTRMark = @"\u200e"; // left-to-right mark 27 | static NSString *RTLMark = @"\u200f"; // right-to-left mark 28 | 29 | // The following only work on iOS 10+ 30 | static NSString *LTRIsolate = @"\u2066"; // left-to-right isolate 31 | static NSString *RTLIsolate = @"\u2067"; // right-to-left isolate 32 | static NSString *FirstStrongIsolate = @"\u2068"; // first strong isolate 33 | static NSString *PopIsolate = @"\u2069"; // pop directional isolate 34 | 35 | 36 | @interface BidirectionalViewController () 37 | 38 | @property (weak, nonatomic) IBOutlet UILabel *labelOne; 39 | @property (weak, nonatomic) IBOutlet UILabel *labelTwo; 40 | @property (weak, nonatomic) IBOutlet UILabel *labelThree; 41 | @property (weak, nonatomic) IBOutlet UILabel *labelFour; 42 | @property (weak, nonatomic) IBOutlet UILabel *labelFive; 43 | 44 | @end 45 | 46 | @implementation BidirectionalViewController 47 | 48 | - (void)viewDidLoad { 49 | [super viewDidLoad]; 50 | 51 | // The following lines will display a (: if the markers are supported, ): if not. 52 | self.labelOne.text = 53 | [NSString stringWithFormat:@"Bidi Isolate supported %@)%@:", RTLIsolate, PopIsolate]; 54 | self.labelTwo.text = 55 | [NSString stringWithFormat:@"Bidi Embed supported %@)%@:", RTLEmbedding, BidiPopEmbedding]; 56 | 57 | // Format a restaurant reservation as [Name] [Number of attendees] @ [time] 58 | // NSString *restaurantName = @"Cancun"; // Latin script 59 | NSString *restaurantName = @"מסעדת מגדלנה במגדל"; // Hebrew script 60 | NSInteger attendees = 4; 61 | NSTimeInterval futureInterval = 60. * 112; // 60 seconds * 122 minutes 62 | NSDate *reservationTime = [NSDate dateWithTimeIntervalSinceNow:futureInterval]; 63 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 64 | dateFormatter.dateStyle = NSDateFormatterNoStyle; 65 | dateFormatter.timeStyle = NSDateFormatterShortStyle; 66 | NSString *reservationTimeString = [dateFormatter stringFromDate:reservationTime]; 67 | 68 | NSString *unwrappedString = [NSString stringWithFormat:@"%@ : %ld @ %@", restaurantName, attendees, reservationTimeString]; 69 | self.labelFour.text = unwrappedString; 70 | 71 | // The same string after wrapping the name 72 | NSString *wrappedRestaurantName = 73 | [restaurantName mdf_stringWithStereoReset:NSLocaleLanguageDirectionRightToLeft 74 | context:NSLocaleLanguageDirectionLeftToRight]; 75 | NSString *wrappedString = [NSString stringWithFormat:@"%@ : %ld @ %@", wrappedRestaurantName, attendees, reservationTimeString]; 76 | self.labelFive.text = wrappedString; 77 | 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/CountryCell.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface CountryCell : UITableViewCell 20 | 21 | @property (weak, nonatomic) IBOutlet UIImageView *flagView; 22 | @property (weak, nonatomic) IBOutlet UILabel *nameLabel; 23 | @property (weak, nonatomic) IBOutlet UIImageView *speechIcon; 24 | 25 | @property (nonatomic, assign, getter=isSpeakingName) BOOL speakingName; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/CountryCell.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "CountryCell.h" 18 | 19 | #import "MDFInternationalization.h" 20 | 21 | @implementation CountryCell 22 | 23 | // Mirroring images could take a non-trivial amount of time to create, so we cache the images. 24 | static UIImage *sSpeakingIcon; 25 | static UIImage *sNonspeakingIcon; 26 | 27 | - (void)awakeFromNib { 28 | [super awakeFromNib]; 29 | 30 | // A flag imageview should not be mirrored in Right-to-Left so we force the view to Left-to-Right. 31 | self.flagView.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight; 32 | 33 | // The speech indicator icon can be mirrored, so we keep the default of 34 | // UISemanticContentAttributeUnspecified. 35 | // self.speechIcon.semanticContentAttribute = UISemanticContentAttributeUnspecified; 36 | 37 | // Our country name label takes up the middle of our cell, but will automatically align the 38 | // text based on it's default textAlignment of NSTextAlignmentNatural. So we leave its 39 | // semanticContentAttribute value as the default UISemanticContentAttributeUnspecified. 40 | // self.nameLabel.semanticContentAttribute = UISemanticContentAttributeUnspecified; 41 | 42 | // Mirroring images could take a non-trivial amount of time, so we cache the resulting images. 43 | static dispatch_once_t onceToken; 44 | dispatch_once(&onceToken, ^{ 45 | sSpeakingIcon = [UIImage imageNamed:@"Speaking"]; 46 | sNonspeakingIcon = [UIImage imageNamed:@"Nonspeaking"]; 47 | if (self.speechIcon.mdf_effectiveUserInterfaceLayoutDirection != 48 | UIUserInterfaceLayoutDirectionLeftToRight) { 49 | sSpeakingIcon = [sSpeakingIcon mdf_imageWithHorizontallyFlippedOrientation]; 50 | sNonspeakingIcon = [sNonspeakingIcon mdf_imageWithHorizontallyFlippedOrientation]; 51 | } 52 | }); 53 | } 54 | 55 | - (void)layoutSubviews { 56 | // We manually calculate the frames for the views in our country cell 57 | CGFloat flagWidth = ceil(CGRectGetWidth(self.bounds) * 0.25); 58 | CGFloat flagHeight = CGRectGetHeight(self.bounds); 59 | CGRect flagFrame = CGRectMake(0.0, 0.0, flagWidth, flagHeight); 60 | flagFrame = CGRectInset(flagFrame, 4.0, 4.0); 61 | 62 | CGFloat speakIconWidth = ceil(CGRectGetWidth(self.bounds) * 0.15); 63 | CGFloat speakIconHeight = CGRectGetHeight(self.bounds); 64 | CGRect speechIconFrame = CGRectMake(0.0, 0.0, speakIconWidth, speakIconHeight); 65 | speechIconFrame.origin.x = CGRectGetWidth(self.bounds) - CGRectGetWidth(speechIconFrame); 66 | 67 | CGFloat nameWidth = 68 | CGRectGetWidth(self.bounds) - CGRectGetWidth(flagFrame) - CGRectGetWidth(speechIconFrame); 69 | CGFloat nameHeight = CGRectGetHeight(self.bounds); 70 | CGRect nameFrame = CGRectMake(0.0, 0.0, nameWidth, nameHeight); 71 | nameFrame.origin.x = CGRectGetMaxX(flagFrame); 72 | nameFrame = CGRectInset(nameFrame, 4.0, 0.0); 73 | 74 | // Mirror the framges if we are in RightToLeft mode. 75 | if (self.mdf_effectiveUserInterfaceLayoutDirection != UIUserInterfaceLayoutDirectionLeftToRight) { 76 | flagFrame = MDFRectFlippedHorizontally(flagFrame, CGRectGetWidth(self.bounds)); 77 | nameFrame = MDFRectFlippedHorizontally(nameFrame, CGRectGetWidth(self.bounds)); 78 | speechIconFrame = MDFRectFlippedHorizontally(speechIconFrame, CGRectGetWidth(self.bounds)); 79 | } 80 | 81 | // Set the view frames 82 | self.flagView.frame = flagFrame; 83 | self.nameLabel.frame = nameFrame; 84 | self.speechIcon.frame = speechIconFrame; 85 | } 86 | 87 | // Adjust our speech indicator if we are actively speaking the name of the country. 88 | - (void)setSpeakingName:(BOOL)speakingName { 89 | if (speakingName) { 90 | self.speechIcon.image = sSpeakingIcon; 91 | } else { 92 | self.speechIcon.image = sNonspeakingIcon; 93 | } 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/CountryTableViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | @interface CountryTableViewController : UITableViewController 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/CountryTableViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "CountryTableViewController.h" 18 | 19 | #import 20 | 21 | #import "CountryCell.h" 22 | 23 | @interface CountryTableViewController () 24 | 25 | @end 26 | 27 | @implementation CountryTableViewController { 28 | NSArray *_countryCodes; 29 | NSMutableArray *_flagImages; 30 | 31 | AVSpeechSynthesizer *_speechSynthesizer; 32 | NSMutableArray *_speakingCellIndexes; 33 | } 34 | 35 | - (void)viewDidLoad { 36 | [super viewDidLoad]; 37 | 38 | _countryCodes = @[ @"ARG", @"AUS", @"BTN", @"CAN", @"FRA", @"GRC", @"IND", @"JAM", @"JPN", @"MEX", 39 | @"NPL", @"PNG", @"QAT", @"SVK", @"TUN", @"USA", @"ZAF", @"ZMB" ]; 40 | 41 | _flagImages = [[NSMutableArray alloc] initWithCapacity:_countryCodes.count]; 42 | for (NSString *countryCode in _countryCodes) { 43 | UIImage *image = [UIImage imageNamed:countryCode]; 44 | [_flagImages addObject:image]; 45 | } 46 | 47 | _speakingCellIndexes = [[NSMutableArray alloc] init]; 48 | 49 | _speechSynthesizer = [[AVSpeechSynthesizer alloc] init]; 50 | _speechSynthesizer.delegate = self; 51 | } 52 | 53 | - (void)viewDidAppear:(BOOL)animated { 54 | [super viewDidAppear:animated]; 55 | if (_speechSynthesizer.isPaused) { 56 | [_speechSynthesizer continueSpeaking]; 57 | } 58 | } 59 | 60 | #pragma mark - UITableViewDataSource 61 | 62 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 63 | return 1; 64 | } 65 | 66 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 67 | return _countryCodes.count; 68 | } 69 | 70 | - (UITableViewCell *)tableView:(UITableView *)tableView 71 | cellForRowAtIndexPath:(NSIndexPath *)indexPath { 72 | // NOTE: The string below must match the prototype cell identifier in the storyboard 73 | CountryCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CountryCell"]; 74 | 75 | NSString *countryCode = _countryCodes[indexPath.row]; 76 | UIImage *flagImage = _flagImages[indexPath.row]; 77 | 78 | // Country names are taken from the Countries.strings file 79 | NSString *name = NSLocalizedStringFromTable(countryCode, @"Countries", @"ISO3 Country Code"); 80 | 81 | cell.nameLabel.text = name; 82 | cell.flagView.image = flagImage; 83 | 84 | NSIndexPath *speakingIndexPath = [_speakingCellIndexes firstObject]; 85 | if ([speakingIndexPath isEqual:indexPath]) { 86 | cell.speakingName = YES; 87 | } else { 88 | cell.speakingName = NO; 89 | } 90 | 91 | return cell; 92 | } 93 | 94 | #pragma mark - UITableViewDelegate 95 | 96 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 97 | NSString *countryCode = _countryCodes[indexPath.row]; 98 | NSString *name = NSLocalizedStringFromTable(countryCode, @"Countries", @"ISO3 Country Code"); 99 | 100 | AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:name]; 101 | [_speechSynthesizer speakUtterance:utterance]; 102 | 103 | [_speakingCellIndexes addObject:indexPath]; 104 | } 105 | 106 | #pragma mark - AVSpeechSynthesizerDelegate 107 | 108 | - (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer 109 | willSpeakRangeOfSpeechString:(NSRange)characterRange 110 | utterance:(AVSpeechUtterance *)utterance { 111 | NSIndexPath *indexPath = [_speakingCellIndexes firstObject]; 112 | if (indexPath && [self.tableView.indexPathsForVisibleRows containsObject:indexPath]) { 113 | CountryCell *cell = 114 | (CountryCell *)[self tableView:self.tableView cellForRowAtIndexPath:indexPath]; 115 | cell.speakingName = YES; 116 | 117 | [self.tableView beginUpdates]; 118 | [self.tableView reloadRowsAtIndexPaths:@[ indexPath ] 119 | withRowAnimation:UITableViewRowAnimationNone]; 120 | [self.tableView endUpdates]; 121 | } 122 | } 123 | 124 | - (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer 125 | didFinishSpeechUtterance:(AVSpeechUtterance *)utterance { 126 | NSIndexPath *indexPath = [_speakingCellIndexes firstObject]; 127 | if (indexPath) { 128 | [_speakingCellIndexes removeObjectAtIndex:0]; 129 | 130 | // Set speech icon back to normal when the country's name is finished being spoken 131 | if ([self.tableView.indexPathsForVisibleRows containsObject:indexPath]) { 132 | CountryCell *cell = 133 | (CountryCell *)[self tableView:self.tableView cellForRowAtIndexPath:indexPath]; 134 | cell.speakingName = NO; 135 | 136 | [self.tableView beginUpdates]; 137 | [self.tableView reloadRowsAtIndexPaths:@[ indexPath ] 138 | withRowAnimation:UITableViewRowAnimationNone]; 139 | [self.tableView endUpdates]; 140 | } 141 | } 142 | } 143 | 144 | - (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer 145 | didCancelSpeechUtterance:(AVSpeechUtterance *)utterance { 146 | // If the version of iOS is too old (~8.1 or earlier), we may be unable to speak country names. 147 | // In that case, present an alert to the user. 148 | NSIndexPath *indexPath = [_speakingCellIndexes firstObject]; 149 | if (indexPath) { 150 | [_speakingCellIndexes removeObjectAtIndex:0]; 151 | } 152 | 153 | static dispatch_once_t onceToken; 154 | dispatch_once(&onceToken, ^{ 155 | NSString *alertTitle = 156 | NSLocalizedString(@"Speech Error", @"Speech Error Alert Title"); 157 | NSString *alertMessage = 158 | NSLocalizedString(@"Unable to speak country names", @"Speech Error Alert Message"); 159 | UIAlertController *alertController = 160 | [UIAlertController alertControllerWithTitle:alertTitle 161 | message:alertMessage 162 | preferredStyle:UIAlertControllerStyleAlert]; 163 | NSString *actionTitle = NSLocalizedString(@"Dismiss", @"Speech Error Alert Dismiss"); 164 | UIAlertAction *dismissAction = 165 | [UIAlertAction actionWithTitle:actionTitle 166 | style:UIAlertActionStyleCancel 167 | handler:^(UIAlertAction * _Nonnull action) { 168 | [self dismissViewControllerAnimated:YES completion:nil]; 169 | }]; 170 | [alertController addAction:dismissAction]; 171 | 172 | [self presentViewController:alertController animated:YES completion:nil]; 173 | }); 174 | } 175 | 176 | @end 177 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ARG.imageset/ARG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ARG.imageset/ARG.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ARG.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "ARG.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/AUS.imageset/AUS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/AUS.imageset/AUS.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/AUS.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "AUS.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/BTN.imageset/BTN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/BTN.imageset/BTN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/BTN.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "BTN.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/CAN.imageset/CAN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/CAN.imageset/CAN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/CAN.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "CAN.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/FRA.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "FRA.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/FRA.imageset/FRA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/FRA.imageset/FRA.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/GRC.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "GRC.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/GRC.imageset/GRC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/GRC.imageset/GRC.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/IND.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "IND.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/IND.imageset/IND.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/IND.imageset/IND.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/JAM.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "JAM.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/JAM.imageset/JAM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/JAM.imageset/JAM.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/JPN.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "JPN.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/JPN.imageset/JPN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/JPN.imageset/JPN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/MEX.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "MEX.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/MEX.imageset/MEX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/MEX.imageset/MEX.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/NPL.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "NPL.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/NPL.imageset/NPL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/NPL.imageset/NPL.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/PNG.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "PNG.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/PNG.imageset/PNG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/PNG.imageset/PNG.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/QAT.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "QAT.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/QAT.imageset/QAT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/QAT.imageset/QAT.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/SVK.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "SVK.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/SVK.imageset/SVK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/SVK.imageset/SVK.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/TUN.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "TUN.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/TUN.imageset/TUN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/TUN.imageset/TUN.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/USA.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "USA.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/USA.imageset/USA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/USA.imageset/USA.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ZAF.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "ZAF.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ZAF.imageset/ZAF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ZAF.imageset/ZAF.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ZMB.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "ZMB.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ZMB.imageset/ZMB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/material-foundation/material-internationalization-ios/305aa8d276f5137c98c5c1c888efc22e02251ee7/Examples/Flags/MDFInternationalizationExample/Flags.xcassets/ZMB.imageset/ZMB.png -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Flags 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/InformationViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface InformationViewController : UIViewController 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/InformationViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "InformationViewController.h" 18 | 19 | #import "MDFInternationalization.h" 20 | 21 | @interface InformationViewController () 22 | @property (weak, nonatomic) IBOutlet UILabel *deviceLabel; 23 | @property (weak, nonatomic) IBOutlet UILabel *OSVersionLabel; 24 | @property (weak, nonatomic) IBOutlet UILabel *localeLabel; 25 | @property (weak, nonatomic) IBOutlet UILabel *LTRRTLLabel; 26 | @property (weak, nonatomic) IBOutlet UIImageView *originalImage; 27 | @property (weak, nonatomic) IBOutlet UIImageView *flippedImage; 28 | @property (weak, nonatomic) IBOutlet UIImageView *twiceFlippedImage; 29 | @property (weak, nonatomic) IBOutlet UIImageView *originalLTRImage; 30 | @property (weak, nonatomic) IBOutlet UIImageView *flippedLTRImage; 31 | @property (weak, nonatomic) IBOutlet UIImageView *twiceFlippedLTRImage; 32 | @property (weak, nonatomic) IBOutlet UIImageView *originalRTLImage; 33 | @property (weak, nonatomic) IBOutlet UIImageView *flippedRTLImage; 34 | @property (weak, nonatomic) IBOutlet UIImageView *twiceFlippedRTLImage; 35 | 36 | @end 37 | 38 | static NSString *sWikipediaURL = @"https://wikipedia.org"; 39 | 40 | @implementation InformationViewController 41 | 42 | - (void)viewDidLoad { 43 | [super viewDidLoad]; 44 | // Do any additional setup after loading the view. 45 | 46 | self.deviceLabel.text = [UIDevice currentDevice].name; 47 | NSString *versionString = [NSString stringWithFormat:@"%@ - %@ %@", 48 | [UIDevice currentDevice].localizedModel, 49 | [UIDevice currentDevice].systemName, 50 | [UIDevice currentDevice].systemVersion]; 51 | self.OSVersionLabel.text = versionString; 52 | NSString *localeIdentifier = [NSLocale currentLocale].localeIdentifier; 53 | NSString *displayLocaleName = 54 | [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:localeIdentifier]; 55 | NSString *localeString; 56 | if (displayLocaleName) { 57 | localeString = [NSString stringWithFormat:@"%@ - %@", localeIdentifier, displayLocaleName]; 58 | } else { 59 | localeString = localeIdentifier; 60 | } 61 | 62 | self.localeLabel.text = localeString; 63 | NSString *userInterfaceLayoutDirectionString; 64 | if ([UIApplication sharedApplication].userInterfaceLayoutDirection 65 | == UIUserInterfaceLayoutDirectionLeftToRight) { 66 | userInterfaceLayoutDirectionString = NSLocalizedString(@"LeftToRight", @"LeftToRight"); 67 | } else { 68 | userInterfaceLayoutDirectionString = NSLocalizedString(@"RightToLeft", @"RightToLeft"); 69 | } 70 | self.LTRRTLLabel.text = userInterfaceLayoutDirectionString; 71 | 72 | UIImage *standardImage = [UIImage imageNamed:@"Standard"]; 73 | UIImage *flippedImage = [standardImage mdf_imageWithHorizontallyFlippedOrientation]; 74 | UIImage *twiceFlippedImage = [flippedImage mdf_imageWithHorizontallyFlippedOrientation]; 75 | 76 | self.originalImage.image = standardImage; 77 | self.originalLTRImage.image = standardImage; 78 | self.originalRTLImage.image = standardImage; 79 | 80 | self.flippedImage.image = flippedImage; 81 | self.flippedLTRImage.image = flippedImage; 82 | self.flippedRTLImage.image = flippedImage; 83 | 84 | self.twiceFlippedImage.image = twiceFlippedImage; 85 | self.twiceFlippedLTRImage.image = twiceFlippedImage; 86 | self.twiceFlippedRTLImage.image = twiceFlippedImage; 87 | } 88 | 89 | - (IBAction)navigateToWikipedia:(id)sender { 90 | if ([sender isKindOfClass:[UIButton class]]) { 91 | NSURL *wikipediaURL = [NSURL URLWithString:sWikipediaURL]; 92 | if (wikipediaURL && 93 | [[UIApplication sharedApplication] canOpenURL:wikipediaURL]) { 94 | [[UIApplication sharedApplication] openURL:wikipediaURL]; 95 | } 96 | } 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/ar.lproj/Countries.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Countries.strings 3 | MDFInternationalizationExample 4 | 5 | Created by Ian Gordon on 9/8/16. 6 | Copyright © 2016 Google. All rights reserved. 7 | */ 8 | 9 | "ARG" = "الأرجنتين"; 10 | "AUS" = "استراليا"; 11 | "BTN" = "بوتان"; 12 | "CAN" = "كندا"; 13 | "FRA" = "فرنسا"; 14 | "GRC" = "اليونان"; 15 | "IND" = "الهند"; 16 | "JAM" = "جامايكا"; 17 | "JPN" = "اليابان"; 18 | "MEX" = "المكسيك"; 19 | "NPL" = "نيبال"; 20 | "PNG" = "بابوا غينيا الجديدة"; 21 | "QAT" = "قطر"; 22 | "SVK" = "سلوفاكيا"; 23 | "TUN" = "تونس"; 24 | "USA" = "الولايات المتحدة الأمريكية"; 25 | "ZAF" = "جنوب أفريقيا"; 26 | "ZMB" = "زامبيا"; 27 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/ar.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | MDFInternationalizationExample 4 | 5 | Created by Ian Gordon on 9/29/16. 6 | Copyright © 2016 Google. All rights reserved. 7 | */ 8 | 9 | "CFBundleDisplayName" = "راية"; 10 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/ar.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UILabel"; text = "Attributions"; ObjectID = "mgn-k3-F8V"; */ 3 | "mgn-k3-F8V.text" = "عزو"; 4 | 5 | /* Class = "UILabel"; text = "Flag images generated from SVG files available on wikipedia.org."; ObjectID = "1en-8q-12w"; */ 6 | "1en-8q-12w.text" = "صور العلم ولدت من ملفات SVG المتاحة على wikipedia.org."; 7 | 8 | /* Class = "UIButton"; title = "en.wikipedia.org/wiki/Flag"; ObjectID = "ZNn-wx-pVo"; */ 9 | "ZNn-wx-pVo.normalTitle" = "wikipedia.org"; 10 | 11 | /* Class = "UILabel"; text = "Image Grid"; ObjectID = "XZB-gP-iGc"; */ 12 | "XZB-gP-iGc.text" = "صورة الشبكة"; 13 | 14 | /* Class = "UILabel"; text = "Device Information"; ObjectID = "YG5-ap-qm5"; */ 15 | "YG5-ap-qm5.text" = "معلومات الجهاز"; 16 | 17 | /* Class = "UITabBarItem"; title = "Flags"; ObjectID = "Gq3-Hs-m0C"; */ 18 | "Gq3-Hs-m0C.title" = "راي"; 19 | 20 | /* Class = "UILabel"; text = "Country Name"; ObjectID = "Jbo-SH-SeQ"; */ 21 | "Jbo-SH-SeQ.text" = "Country Name"; 22 | 23 | /* Class = "UITableViewController"; title = "Flags"; ObjectID = "M9q-Kw-lR5"; */ 24 | "M9q-Kw-lR5.title" = "راية"; 25 | 26 | /* Class = "UILabel"; text = "OS Version"; ObjectID = "PgA-Ot-YFF"; */ 27 | "PgA-Ot-YFF.text" = "OS Version"; 28 | 29 | /* Class = "UILabel"; text = "Locale"; ObjectID = "Smi-n9-SyQ"; */ 30 | "Smi-n9-SyQ.text" = "Locale"; 31 | 32 | /* Class = "UILabel"; text = "Device"; ObjectID = "mzM-ln-glZ"; */ 33 | "mzM-ln-glZ.text" = "Device"; 34 | 35 | /* Class = "UITabBarItem"; title = "Info"; ObjectID = "rz9-iM-jLd"; */ 36 | "rz9-iM-jLd.title" = "معلومات"; 37 | 38 | /* Class = "UILabel"; text = "LTR | RTL"; ObjectID = "spj-nM-7Zl"; */ 39 | "spj-nM-7Zl.text" = "LTR | RTL"; 40 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/en.lproj/Countries.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Countries.strings 3 | MDFInternationalizationExample 4 | 5 | Created by Ian Gordon on 9/8/16. 6 | Copyright © 2016 Google. All rights reserved. 7 | */ 8 | 9 | "ARG" = "Argentina"; 10 | "AUS" = "Australia"; 11 | "BTN" = "Bhutan"; 12 | "CAN" = "Canada"; 13 | "FRA" = "France"; 14 | "GRC" = "Greece"; 15 | "IND" = "India"; 16 | "JAM" = "Jamaica"; 17 | "JPN" = "Japan"; 18 | "MEX" = "Mexico"; 19 | "NPL" = "Nepal"; 20 | "PNG" = "Papua New Guinea"; 21 | "QAT" = "Qatar"; 22 | "SVK" = "Slovakia"; 23 | "TUN" = "Tunisia"; 24 | "USA" = "United States of America"; 25 | "ZAF" = "South Africa"; 26 | "ZMB" = "Zambia"; 27 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/en.lproj/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Flags 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | InfoPlist.strings 3 | MDFInternationalizationExample 4 | 5 | Created by Ian Gordon on 9/29/16. 6 | Copyright © 2016 Google. All rights reserved. 7 | */ 8 | 9 | "CFBundleDisplayName" = "Flags"; 10 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/en.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | /* Class = "UILabel"; text = "Attributions"; ObjectID = "mgn-k3-F8V"; */ 2 | "mgn-k3-F8V.text" = "Attributions"; 3 | 4 | /* Class = "UILabel"; text = "Flag images generated from SVG files available on wikipedia.org."; ObjectID = "1en-8q-12w"; */ 5 | "1en-8q-12w.text" = "Flag images generated from SVG files available on wikipedia.org."; 6 | 7 | /* Class = "UIButton"; title = "en.wikipedia.org/wiki/Flag"; ObjectID = "ZNn-wx-pVo"; */ 8 | "ZNn-wx-pVo.normalTitle" = "wikipedia.org"; 9 | 10 | /* Class = "UILabel"; text = "Image Grid"; ObjectID = "XZB-gP-iGc"; */ 11 | "XZB-gP-iGc.text" = "Image Grid"; 12 | 13 | /* Class = "UILabel"; text = "Device Information"; ObjectID = "YG5-ap-qm5"; */ 14 | "YG5-ap-qm5.text" = "Device Information"; 15 | 16 | /* Class = "UITabBarItem"; title = "Flags"; ObjectID = "Gq3-Hs-m0C"; */ 17 | "Gq3-Hs-m0C.title" = "Flags"; 18 | 19 | /* Class = "UILabel"; text = "Country Name"; ObjectID = "Jbo-SH-SeQ"; */ 20 | "Jbo-SH-SeQ.text" = "Country Name"; 21 | 22 | /* Class = "UITableViewController"; title = "Flags"; ObjectID = "M9q-Kw-lR5"; */ 23 | "M9q-Kw-lR5.title" = "Flags"; 24 | 25 | /* Class = "UILabel"; text = "OS Version"; ObjectID = "PgA-Ot-YFF"; */ 26 | "PgA-Ot-YFF.text" = "OS Version"; 27 | 28 | /* Class = "UILabel"; text = "Locale"; ObjectID = "Smi-n9-SyQ"; */ 29 | "Smi-n9-SyQ.text" = "Locale"; 30 | 31 | /* Class = "UILabel"; text = "Device"; ObjectID = "mzM-ln-glZ"; */ 32 | "mzM-ln-glZ.text" = "Device"; 33 | 34 | /* Class = "UITabBarItem"; title = "Info"; ObjectID = "rz9-iM-jLd"; */ 35 | "rz9-iM-jLd.title" = "Info"; 36 | 37 | /* Class = "UILabel"; text = "LTR | RTL"; ObjectID = "spj-nM-7Zl"; */ 38 | "spj-nM-7Zl.text" = "LTR | RTL"; 39 | -------------------------------------------------------------------------------- /Examples/Flags/MDFInternationalizationExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AppDelegate.h" 3 | 4 | int main(int argc, char * argv[]) { 5 | @autoreleasepool { 6 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /MDFInternationalization.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "MDFInternationalization" 3 | s.version = "3.0.0" 4 | s.authors = "The Material Foundation Authors" 5 | s.summary = "Internationalization tools." 6 | s.homepage = "https://github.com/material-foundation/material-internationalization-ios" 7 | s.license = "Apache License, Version 2.0" 8 | s.source = { :git => "https://github.com/material-foundation/material-internationalization-ios.git", :tag => "v#{s.version}" } 9 | s.platform = :ios, "11.0" 10 | 11 | s.requires_arc = true 12 | s.public_header_files = "Sources/*.h" 13 | s.source_files = "Sources/*.{h,m}" 14 | s.header_mappings_dir = "Sources" 15 | s.header_dir = "MDFInternationalization" 16 | end 17 | -------------------------------------------------------------------------------- /MDFInternationalization.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MDFInternationalization.xcodeproj/xcshareddata/xcschemes/MDFInternationalization.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /MDFInternationalization.xcodeproj/xcshareddata/xcschemes/MDFInternationalizationTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | 43 | 49 | 50 | 52 | 53 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /MDFInternationalization.xcodeproj/xcuserdata/iangordon.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MDFInternationalization.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | MDFInternationalization.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | MDFInternationalizationTests.xcscheme 18 | 19 | orderHint 20 | 1 21 | 22 | MDFInternationalizationTests.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 1 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 4096E5AE1D78CB5500389ECD 31 | 32 | primary 33 | 34 | 35 | 4096E5B81D78CB5500389ECD 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MDFInternationalization 2 | 3 | MDFInternationalization assists in internationalizing your iOS app or components' user interface. 4 | 5 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/material-foundation/material-internationalization-ios/blob/develop/LICENSE) 6 | [![GitHub release](https://img.shields.io/github/release/material-foundation/material-internationalization-ios.svg)](https://github.com/material-foundation/material-internationalization-ios/releases) 7 | [![Build Status](https://travis-ci.org/material-foundation/material-internationalization-ios.svg?branch=stable)](https://travis-ci.org/material-foundation/material-internationalization-ios) 8 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/MDFInternationalization.svg)](https://img.shields.io/cocoapods/v/MDFInternationalization.svg) 9 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 10 | 11 | ## Right-to-Left calculations for CGRects and UIEdgeInsets 12 | 13 | A UIView is positioned within its superview in terms of a frame (CGRect) consisting of an 14 | origin and a size. When a device is set to a language that is written from Right-to-Left (RTL), 15 | we often want to mirror the interface around the vertical axis. This library contains 16 | functions to assist in modifying frames and edge insets for RTL. 17 | 18 | ``` obj-c 19 | // To flip a subview's frame horizontally, pass in subview.frame and the width of its parent. 20 | CGRect originalFrame = childView.frame; 21 | CGRect flippedFrame = MDFRectFlippedHorizontally(originalFrame, CGRectGetWidth(self.bounds)); 22 | childView.frame = flippedFrame; 23 | ``` 24 | 25 | ## Mirroring Images 26 | 27 | A category on UIImage backports iOS 10's `[UIImage imageWithHorizontallyFlippedOrientation]` to 28 | earlier versions of iOS. 29 | 30 | ``` obj-c 31 | // To mirror on image, invoke mdf_imageWithHorizontallyFlippedOrientation. 32 | UIImage *mirroredImage = [originalImage mdf_imageWithHorizontallyFlippedOrientation]; 33 | ``` 34 | 35 | ## Adding semantic context 36 | 37 | A category on UIView backports iOS 9's `-[UIView semanticContentAttribute]` and iOS 10's 38 | `-[UIView effectiveUserInterfaceLayoutDirection]` to earlier versions of iOS. 39 | 40 | ``` obj-c 41 | // To set a semantic content attribute, set the mdf_semanticContentAttribute property. 42 | lockedLTRView.mdf_semanticContentAttribute = UISemanticContentAttributeForceLeftToRight; 43 | 44 | // mdf_semanticContentAttribute is used to calculate the mdf_effectiveUserInterfaceLayoutDirection 45 | if (customView.mdf_effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) { 46 | // Update customView's layout to be in RTL mode. 47 | } 48 | ``` 49 | 50 | ## Embedding Bi-directional strings 51 | 52 | A category on NSString offers a simple API to wrap strings in Unicode markers so that LTR 53 | and RTL text can co-exist in the same string. 54 | 55 | ``` obj-c 56 | // To embed an RTL string in an existing LTR string we should wrap it in Unicode directionality 57 | // markers to maintain preoper rendering. 58 | 59 | // The name of a restaurant is in Arabic (RTL), but the rest of string is in Latin (LTR). 60 | NSString *wrappedRestaurantName = 61 | [restaurantName mdf_stringWithStereoReset:NSLocaleLanguageDirectionRightToLeft 62 | context:NSLocaleLanguageDirectionLeftToRight]; 63 | 64 | NSString *reservationString = [NSString stringWithFormat:@"%@ : %ld", wrappedRestaurantName, attendees]; 65 | ``` 66 | 67 | ## Usage 68 | 69 | See Examples/Flags for a detailed example of how to use the functionality provided by this library. 70 | 71 | 72 | ## License 73 | 74 | MDFInternationalization is licensed under the [Apache License Version 2.0](LICENSE). 75 | -------------------------------------------------------------------------------- /Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/MDFInternationalization.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "MDFRTL.h" // IWYU pragma: keep 20 | #import "NSLocale+MaterialRTL.h" // IWYU pragma: keep 21 | #import "NSString+MaterialBidi.h" // IWYU pragma: keep 22 | #import "UIImage+MaterialRTL.h" // IWYU pragma: keep 23 | #import "UIView+MaterialRTL.h" // IWYU pragma: keep 24 | 25 | //! Project version number for MDFInternationalization. 26 | FOUNDATION_EXPORT double MDFInternationalizationVersionNumber; 27 | 28 | //! Project version string for MDFInternationalization. 29 | FOUNDATION_EXPORT const unsigned char MDFInternationalizationVersionString[]; 30 | -------------------------------------------------------------------------------- /Sources/MDFRTL.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | /** 20 | Leading autoresizing mask based on layoutDirection. 'Leading' is 'Left' in 21 | UIUserInterfaceLayoutDirectionLeftToRight, 'Right' otherwise. 22 | 23 | @param layoutDirection The layout direction to consider when computing the autoresizing mask. 24 | @return The leading margin part of an autoresizing mask. 25 | */ 26 | FOUNDATION_EXPORT UIViewAutoresizing MDFLeadingMarginAutoresizingMaskForLayoutDirection( 27 | UIUserInterfaceLayoutDirection layoutDirection); 28 | 29 | /** 30 | Trailing autoresizing masks based on layoutDirection. 'Trailing' is 'Right' in 31 | UIUserInterfaceLayoutDirectionLeftToRight, 'Left' otherwise. 32 | 33 | @param layoutDirection The layout direction to consider to compute the autoresizing mask. 34 | @return The trailing margin part of an autoresizing mask. 35 | */ 36 | FOUNDATION_EXPORT UIViewAutoresizing MDFTrailingMarginAutoresizingMaskForLayoutDirection( 37 | UIUserInterfaceLayoutDirection layoutDirection); 38 | 39 | /** 40 | The frame to use when actually laying out a view in its superview. 41 | 42 | A view is conceptually positioned within its superview in terms of leading/trailing. When it's time 43 | to actually lay out (i.e. setting frames), you position the frame as you usually would, but if you 44 | are in the opposite layout direction you call this function to return a rect that has been flipped 45 | around the vertical axis. 46 | 47 | @note Example: Flipping the frame of a subview 50pts wide at 10pts from the leading edge of a 48 | bounding view. 49 | 50 | CGRect frame = CGRectMake(10, originY, 50, height); 51 | CGFloat containerWidth = CGRectGetWidth(self.bounds); 52 | if (layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) { 53 | frame = MDFRectFlippedHorizontally(frame, containerWidth); 54 | } 55 | 56 | In LTR, frame is { { 10, originY }, { 50, height } } in a 100 wide bounding view. 57 | +----------------------------------------100----------------------------------------+ 58 | | | 59 | | 10 +--------------------50--------------------+ | 60 | | | | | 61 | | +------------------------------------------+ | 62 | | | 63 | +----------------------------------------100----------------------------------------+ 64 | 65 | In RTL, frame is { { 40, originY }, { 50, height } }. 66 | +----------------------------------------100----------------------------------------+ 67 | | | 68 | | 40 +--------------------50--------------------+ | 69 | | | | | 70 | | +------------------------------------------+ | 71 | | | 72 | +----------------------------------------100----------------------------------------+ 73 | 74 | @param frame The frame to convert. 75 | @param containerWidth The superview's bounds's width. 76 | @return The frame mirrored around the vertical axis. 77 | */ 78 | FOUNDATION_EXPORT CGRect MDFRectFlippedHorizontally(CGRect frame, CGFloat containerWidth); 79 | 80 | 81 | /** 82 | Creates a UIEdgeInsets instance with its left and right values exchanged. 83 | 84 | @param insets The insets we are intending to flip horizontally. 85 | @return Insets with the right and left values exchanged. 86 | */ 87 | FOUNDATION_EXPORT UIEdgeInsets MDFInsetsFlippedHorizontally(UIEdgeInsets insets); 88 | 89 | /** 90 | Creates a UIEdgeInsets instance from the parameters while obeying layoutDirection. 91 | 92 | If layoutDirection is UIUserInterfaceLayoutDirectionLeftToRight, then the left inset is leading and 93 | the right inset is trailing, otherwise they are reversed. 94 | 95 | @param top The top inset. 96 | @param leading The leading inset. 97 | @param bottom The bottom inset. 98 | @param trailing The trailing inset. 99 | @return Insets in terms of left/right, already internationalized based on the layout direction. 100 | */ 101 | FOUNDATION_EXPORT UIEdgeInsets MDFInsetsMakeWithLayoutDirection(CGFloat top, 102 | CGFloat leading, 103 | CGFloat bottom, 104 | CGFloat trailing, 105 | UIUserInterfaceLayoutDirection layoutDirection); 106 | -------------------------------------------------------------------------------- /Sources/MDFRTL.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "MDFRTL.h" 18 | 19 | UIViewAutoresizing MDFLeadingMarginAutoresizingMaskForLayoutDirection( 20 | UIUserInterfaceLayoutDirection layoutDirection) { 21 | switch (layoutDirection) { 22 | case UIUserInterfaceLayoutDirectionLeftToRight: 23 | return UIViewAutoresizingFlexibleLeftMargin; 24 | case UIUserInterfaceLayoutDirectionRightToLeft: 25 | return UIViewAutoresizingFlexibleRightMargin; 26 | } 27 | NSCAssert(NO, @"Invalid enumeration value %i.", (int)layoutDirection); 28 | return UIViewAutoresizingFlexibleLeftMargin; 29 | } 30 | 31 | UIViewAutoresizing MDFTrailingMarginAutoresizingMaskForLayoutDirection( 32 | UIUserInterfaceLayoutDirection layoutDirection) { 33 | switch (layoutDirection) { 34 | case UIUserInterfaceLayoutDirectionLeftToRight: 35 | return UIViewAutoresizingFlexibleRightMargin; 36 | case UIUserInterfaceLayoutDirectionRightToLeft: 37 | return UIViewAutoresizingFlexibleLeftMargin; 38 | } 39 | NSCAssert(NO, @"Invalid enumeration value %i.", (int)layoutDirection); 40 | return UIViewAutoresizingFlexibleRightMargin; 41 | } 42 | 43 | CGRect MDFRectFlippedHorizontally(CGRect frame, CGFloat containerWidth) { 44 | CGRect flippedRect = CGRectStandardize(frame); 45 | CGFloat leadingInset = CGRectGetMinX(flippedRect); 46 | CGFloat width = CGRectGetWidth(flippedRect); 47 | flippedRect.origin.x = containerWidth - leadingInset - width; 48 | 49 | return flippedRect; 50 | } 51 | 52 | UIEdgeInsets MDFInsetsFlippedHorizontally(UIEdgeInsets insets) { 53 | UIEdgeInsets flippedInsets = insets; 54 | flippedInsets.left = insets.right; 55 | flippedInsets.right = insets.left; 56 | 57 | return flippedInsets; 58 | } 59 | 60 | UIEdgeInsets MDFInsetsMakeWithLayoutDirection(CGFloat top, 61 | CGFloat leading, 62 | CGFloat bottom, 63 | CGFloat trailing, 64 | UIUserInterfaceLayoutDirection layoutDirection) { 65 | switch (layoutDirection) { 66 | case UIUserInterfaceLayoutDirectionLeftToRight: 67 | return UIEdgeInsetsMake(top, leading, bottom, trailing); 68 | case UIUserInterfaceLayoutDirectionRightToLeft: 69 | return UIEdgeInsetsMake(top, trailing, bottom, leading); 70 | } 71 | NSCAssert(NO, @"Invalid enumeration value %i.", (int)layoutDirection); 72 | return UIEdgeInsetsMake(top, leading, bottom, trailing); 73 | } 74 | -------------------------------------------------------------------------------- /Sources/NSLocale+MaterialRTL.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface NSLocale (MaterialRTL) 20 | 21 | /** 22 | Is the direction of the current locale's default language Left-To-Right? 23 | 24 | @return YES if the language is LTR, NO if the language is any other direction. 25 | */ 26 | + (BOOL)mdf_isDefaultLanguageLTR; 27 | 28 | /** 29 | Is the direction of the current locale's default language Right-To-Left? 30 | 31 | @return YES if the language is RTL, NO if the language is any other direction. 32 | */ 33 | + (BOOL)mdf_isDefaultLanguageRTL; 34 | 35 | @end 36 | 37 | -------------------------------------------------------------------------------- /Sources/NSLocale+MaterialRTL.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSLocale+MaterialRTL.h" 18 | 19 | @implementation NSLocale (MaterialRTL) 20 | 21 | + (BOOL)mdf_isDefaultLanguageLTR { 22 | NSString *languageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]; 23 | NSLocaleLanguageDirection characterDirection = 24 | [NSLocale characterDirectionForLanguage:languageCode]; 25 | BOOL localeLanguageDirectionIsLTR = (characterDirection == NSLocaleLanguageDirectionLeftToRight); 26 | return localeLanguageDirectionIsLTR; 27 | } 28 | 29 | + (BOOL)mdf_isDefaultLanguageRTL { 30 | NSString *languageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]; 31 | NSLocaleLanguageDirection characterDirection = 32 | [NSLocale characterDirectionForLanguage:languageCode]; 33 | BOOL localeLanguageDirectionIsRTL = (characterDirection == NSLocaleLanguageDirectionRightToLeft); 34 | return localeLanguageDirectionIsRTL; 35 | } 36 | 37 | @end 38 | 39 | -------------------------------------------------------------------------------- /Sources/NSString+MaterialBidi.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface NSString (MaterialBidi) 20 | 21 | /** 22 | Uses CFStringTokenizerCopyBestStringLanguage to determine string's language direction. 23 | If the language direction is unknown or vertical returns left-to-right. 24 | 25 | As CFStringTokenizerCopyBestStringLanguage is Apple's API, its result may change if 26 | Apple improves or modifies the implementation. 27 | 28 | @return the direction of the string 29 | */ 30 | - (NSLocaleLanguageDirection)mdf_calculatedLanguageDirection; 31 | 32 | /** 33 | Initializes a copy of the string tagged with the given language direction. This 34 | formatting adds the appropriate Unicode embedding characters at the beginning and end of the 35 | string. 36 | 37 | Only NSLocaleLanguageDirectionLeftToRight and NSLocaleLanguageDirectionRightToLeft 38 | language directions are supported. Other values of NSLocalLanguageDirection will 39 | return a copy of self. 40 | 41 | Returns a string wrapped with Unicode bidi formatting characters by inserting these characters 42 | around the string: 43 | RLE+|string|+PDF for RTL text, or LRE+|string|+PDF for LTR text. 44 | 45 | @returns the new string. 46 | */ 47 | - (nonnull NSString *)mdf_stringWithBidiEmbedding:(NSLocaleLanguageDirection)languageDirection; 48 | 49 | /** 50 | Returns a copy of the string explicitly tagged with a language direction. 51 | 52 | Uses mdf_calculatedLanguageDirection to determine string's language direction then invokes 53 | mdf_stringWithBidiEmbedding:. 54 | 55 | @return the new string. 56 | */ 57 | - (nonnull NSString *)mdf_stringWithBidiEmbedding; 58 | 59 | /** 60 | This method will wrap the string in embedding (LRE/RLE and PDF) characters, based on the string 61 | direction and additionally wrapping the string in marks (LRM and RLM) if the string's direction 62 | is different from the context direction. 63 | 64 | |direction| can be NSLocaleLanguageDirectionLeftToRight, NSLocaleLanguageDirectionRightToLeft, or 65 | NSLocaleLanguageDirectionUnknown. If NSLocaleLanguageDirectionUnknown, the direction of the string 66 | will be calculated with mdf_calculatedLanguageDirection. 67 | 68 | |contextDirection| must be specified and cannot be unknown. Only 69 | NSLocaleLanguageDirectionLeftToRight and NSLocaleLanguageDirectionRightToLeft language directions 70 | are supported. 71 | 72 | @returns the new string. 73 | */ 74 | - (nonnull NSString *)mdf_stringWithStereoReset:(NSLocaleLanguageDirection)direction 75 | context:(NSLocaleLanguageDirection)contextDirection; 76 | 77 | /** 78 | Returns a new string in which all occurrences of Unicode bidirectional format markers are removed. 79 | 80 | @returns the new string. 81 | */ 82 | - (nonnull NSString *)mdf_stringWithBidiMarkersStripped; 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /Sources/NSString+MaterialBidi.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSString+MaterialBidi.h" 18 | 19 | #import 20 | 21 | @implementation NSString (MaterialBidi) 22 | 23 | // https://www.w3.org/International/questions/qa-bidi-unicode-controls 24 | //TODO: Reach out to AAA about the utility of the Isolate markers 25 | // ??? Do we want Embedding or Isolate markers? w3 recommends isolate? 26 | // Add reference : Unicode® Standard Annex #9 UNICODE BIDIRECTIONAL ALGORITHM 27 | // go/android-bidiformatter 28 | // http://unicode.org/reports/tr9/ 29 | 30 | // Mark influences the directionality of neutral characters when the context is opposite of the 31 | // neutral chatacter's desired directionality. 32 | static NSString *kMDFLTRMark = @"\u200e"; // left-to-right mark 33 | static NSString *kMDFRTLMark = @"\u200f"; // right-to-left mark 34 | 35 | // Embedding indicates a text segment is embedded in a larger context with the opposite 36 | // directionality. 37 | static NSString *kMDFLTREmbedding = @"\u202a"; // left-to-right embedding 38 | static NSString *kMDFRTLEmbedding = @"\u202b"; // right-to-left embedding 39 | 40 | // Override reverses the directionality of strongly LTR or RTL characters 41 | static NSString *kMDFLTROverride = @"\u202d"; // left-to-right override 42 | static NSString *kMDFRTLOverride = @"\u202e"; // right-to-left override 43 | 44 | // Pop is used to denote the end of an embedding or override text segment 45 | static NSString *kMDFPopFormatting = @"\u202c"; // pop directional formatting 46 | 47 | // Version 6.3.0 Bidi algorithm additions 48 | // The following only work on iOS 10+ 49 | 50 | // Isolate indicates that the text segment has an internal directionality with no effect on 51 | // surrounding characters. 52 | static NSString *kMDFLTRIsolate = @"\u2066"; // left-to-right isolate 53 | static NSString *kMDFRTLIsolate = @"\u2067"; // right-to-left isolate 54 | static NSString *kMDFFirstStrongIsolate = @"\u2068"; // first strong isolate 55 | 56 | // Pop Isolate is used to denote the end of an isolate text segment 57 | static NSString *kMDFPopIsolate = @"\u2069"; // pop directional isolate 58 | 59 | 60 | - (NSLocaleLanguageDirection)mdf_calculatedLanguageDirection { 61 | // Attempt to determine language of string. 62 | NSLocaleLanguageDirection languageDirection = NSLocaleLanguageDirectionUnknown; 63 | 64 | // Pass string into CoreFoundation's language identifier 65 | CFStringRef text = (__bridge CFStringRef)self; 66 | CFRange range = CFRangeMake(0, (CFIndex)[self length]); 67 | NSString *languageCode = 68 | (NSString *)CFBridgingRelease(CFStringTokenizerCopyBestStringLanguage(text, range)); 69 | if (languageCode) { 70 | // If we identified a language, explicitly set the string direction based on that 71 | languageDirection = [NSLocale characterDirectionForLanguage:languageCode]; 72 | } 73 | 74 | // If the result is not LTR or RTL, fallback to LTR 75 | // ??? Should I be defaulting to NSLocale.NSLocaleLanguageCode.characterDiretion? 76 | if (languageDirection != NSLocaleLanguageDirectionLeftToRight && 77 | languageDirection != NSLocaleLanguageDirectionRightToLeft) { 78 | languageDirection = NSLocaleLanguageDirectionLeftToRight; 79 | } 80 | 81 | return languageDirection; 82 | } 83 | 84 | - (NSString *)mdf_stringWithBidiEmbedding { 85 | NSLocaleLanguageDirection languageDirection = [self mdf_calculatedLanguageDirection]; 86 | 87 | return [self mdf_stringWithBidiEmbedding:languageDirection]; 88 | } 89 | 90 | - (NSString *)mdf_stringWithBidiEmbedding:(NSLocaleLanguageDirection)languageDirection { 91 | if (languageDirection == NSLocaleLanguageDirectionRightToLeft) { 92 | return [NSString stringWithFormat:@"%@%@%@", kMDFRTLEmbedding, self, kMDFPopFormatting]; 93 | } else if (languageDirection == NSLocaleLanguageDirectionLeftToRight) { 94 | return [NSString stringWithFormat:@"%@%@%@", kMDFLTREmbedding, self, kMDFPopFormatting]; 95 | } else { 96 | // Return a copy original string if an unsupported direction is passed in. 97 | return [self copy]; 98 | } 99 | } 100 | 101 | - (nonnull NSString *)mdf_stringWithStereoReset:(NSLocaleLanguageDirection)direction 102 | context:(NSLocaleLanguageDirection)contextDirection { 103 | #if DEBUG 104 | // Disable in release, as a pre-caution in case not everyone defines NS_BLOCK_ASSERTION. 105 | NSCAssert((contextDirection != NSLocaleLanguageDirectionLeftToRight || 106 | contextDirection != NSLocaleLanguageDirectionRightToLeft), 107 | @"contextStringDirection must be passed in and set to either" 108 | "NSLocaleLanguageDirectionLeftToRight or NSLocaleLanguageDirectionRightToLeft."); 109 | 110 | NSCAssert((direction != NSLocaleLanguageDirectionLeftToRight || 111 | direction != NSLocaleLanguageDirectionRightToLeft || 112 | direction != NSLocaleLanguageDirectionUnknown), 113 | @"stringToBeInsertedDirection must be set to either NSLocaleLanguageDirectionUnknown," 114 | "NSLocaleLanguageDirectionLeftToRight, or NSLocaleLanguageDirectionRightToLeft."); 115 | #endif 116 | 117 | if (self.length == 0) { 118 | return [self copy]; 119 | } 120 | 121 | if (direction != NSLocaleLanguageDirectionLeftToRight && 122 | direction != NSLocaleLanguageDirectionRightToLeft) { 123 | direction = [self mdf_calculatedLanguageDirection]; 124 | } 125 | 126 | NSString *bidiEmbeddedString = [self mdf_stringWithBidiEmbedding:direction]; 127 | 128 | NSString *bidiResetString; 129 | if (direction != contextDirection) { 130 | if (contextDirection == NSLocaleLanguageDirectionRightToLeft) { 131 | bidiResetString = 132 | [NSString stringWithFormat:@"%@%@%@", kMDFRTLMark, bidiEmbeddedString, kMDFRTLMark]; 133 | } else { 134 | bidiResetString = 135 | [NSString stringWithFormat:@"%@%@%@", kMDFLTRMark, bidiEmbeddedString, kMDFLTRMark]; 136 | } 137 | } else { 138 | bidiResetString = bidiEmbeddedString; 139 | } 140 | 141 | return bidiResetString; 142 | } 143 | 144 | - (NSString *)mdf_stringWithBidiMarkersStripped { 145 | NSString *strippedString = self; 146 | NSArray *directionalMarkers = @[ kMDFLTRMark, 147 | kMDFRTLMark, 148 | kMDFRTLEmbedding, 149 | kMDFLTREmbedding, 150 | kMDFRTLOverride, 151 | kMDFLTROverride, 152 | kMDFPopFormatting, 153 | kMDFLTRIsolate, 154 | kMDFRTLIsolate, 155 | kMDFFirstStrongIsolate, 156 | kMDFPopIsolate 157 | ]; 158 | for (NSString *markerString in directionalMarkers) { 159 | strippedString = 160 | [strippedString stringByReplacingOccurrencesOfString:markerString withString:@""]; 161 | } 162 | return strippedString; 163 | } 164 | 165 | @end 166 | -------------------------------------------------------------------------------- /Sources/UIImage+MaterialRTL.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | /** 20 | Backporting of iOS 10's [UIImage imageWithHorizontallyFlippedOrientation]. 21 | */ 22 | 23 | @interface UIImage (MaterialRTL) 24 | 25 | /** 26 | On iOS 10 and above, calls [UIImage imageWithHorizontallyFlippedOrientation]. 27 | Otherwise manually flips the image and returns the result. 28 | 29 | @return A horizontally mirrored version of this image. 30 | */ 31 | - (nonnull UIImage *)mdf_imageWithHorizontallyFlippedOrientation; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Sources/UIImage+MaterialRTL.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "UIImage+MaterialRTL.h" 18 | 19 | #import 20 | #import 21 | 22 | /** Returns the horizontally flipped version of the given UIImageOrientation. */ 23 | static UIImageOrientation MDFRTLMirroredOrientation(UIImageOrientation sourceOrientation) { 24 | switch (sourceOrientation) { 25 | case UIImageOrientationUp: 26 | return UIImageOrientationUpMirrored; 27 | case UIImageOrientationDown: 28 | return UIImageOrientationDownMirrored; 29 | case UIImageOrientationLeft: 30 | return UIImageOrientationLeftMirrored; 31 | case UIImageOrientationRight: 32 | return UIImageOrientationRightMirrored; 33 | case UIImageOrientationUpMirrored: 34 | return UIImageOrientationUp; 35 | case UIImageOrientationDownMirrored: 36 | return UIImageOrientationDown; 37 | case UIImageOrientationLeftMirrored: 38 | return UIImageOrientationLeft; 39 | case UIImageOrientationRightMirrored: 40 | return UIImageOrientationRight; 41 | } 42 | NSCAssert(NO, @"Invalid enumeration value %i.", (int)sourceOrientation); 43 | return UIImageOrientationUpMirrored; 44 | } 45 | 46 | /** 47 | Returns a copy of the image actually flipped. The orientation and scale are consumed, while the 48 | rendering mode is ported to the new image. 49 | */ 50 | static UIImage *MDFRTLFlippedImage(UIImage *image) { 51 | CGSize size = image.size; 52 | CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); 53 | 54 | UIGraphicsBeginImageContextWithOptions(rect.size, NO, image.scale); 55 | CGContextRef context = UIGraphicsGetCurrentContext(); 56 | CGContextSetShouldAntialias(context, true); 57 | CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 58 | 59 | // Note: UIKit's and CoreGraphics coordinates systems are flipped vertically (UIKit's Y axis goes 60 | // down, while CoreGraphics' goes up). 61 | switch (image.imageOrientation) { 62 | case UIImageOrientationUp: 63 | CGContextScaleCTM(context, -1, -1); 64 | CGContextTranslateCTM(context, -rect.size.width, -rect.size.height); 65 | break; 66 | case UIImageOrientationDown: 67 | // Orientation down is equivalent to a 180º rotation. The difference in coordinates systems is 68 | // thus sufficient and nothing needs to be down to flip the image. 69 | break; 70 | case UIImageOrientationLeft: 71 | CGContextRotateCTM(context, -(CGFloat)M_PI_2); 72 | CGContextTranslateCTM(context, -rect.size.width, 0); 73 | break; 74 | case UIImageOrientationRight: 75 | CGContextRotateCTM(context, (CGFloat)M_PI_2); 76 | CGContextTranslateCTM(context, 0, -rect.size.width); 77 | break; 78 | case UIImageOrientationUpMirrored: 79 | CGContextScaleCTM(context, 1, -1); 80 | CGContextTranslateCTM(context, 0, -rect.size.height); 81 | break; 82 | case UIImageOrientationDownMirrored: 83 | CGContextScaleCTM(context, -1, 1); 84 | CGContextTranslateCTM(context, -rect.size.width, 0); 85 | break; 86 | case UIImageOrientationLeftMirrored: 87 | CGContextRotateCTM(context, -(CGFloat)M_PI_2); 88 | CGContextTranslateCTM(context, -rect.size.width, 0); 89 | CGContextScaleCTM(context, -1, 1); 90 | CGContextTranslateCTM(context, -rect.size.width, 0); 91 | break; 92 | case UIImageOrientationRightMirrored: 93 | CGContextRotateCTM(context, (CGFloat)M_PI_2); 94 | CGContextTranslateCTM(context, 0, -rect.size.width); 95 | CGContextScaleCTM(context, -1, 1); 96 | CGContextTranslateCTM(context, -rect.size.width, 0); 97 | break; 98 | default: 99 | NSCAssert(NO, @"Invalid enumeration value %i.", (int)image.imageOrientation); 100 | } 101 | 102 | // If the UIImage is not backed by a CGImage, create one from the CIImage 103 | if (image.CGImage) { 104 | CGContextDrawImage(context, rect, image.CGImage); 105 | } else if (image.CIImage) { 106 | CIImage *coreImage = image.CIImage; 107 | CIContext *coreImageContext = [CIContext context]; 108 | CGImageRef coreGraphicsImage = 109 | [coreImageContext createCGImage:coreImage fromRect:coreImage.extent]; 110 | if (coreGraphicsImage) { 111 | CGContextDrawImage(context, rect, coreGraphicsImage); 112 | CFRelease(coreGraphicsImage); 113 | coreGraphicsImage = NULL; 114 | } 115 | } else { 116 | NSCAssert(NO, @"Unable to flip image without a CGImage or CIImage backing store"); 117 | } 118 | 119 | UIImage *drawnImage = UIGraphicsGetImageFromCurrentImageContext(); 120 | UIGraphicsEndImageContext(); 121 | 122 | // Port the rendering mode. 123 | UIImage *flippedImage = [drawnImage imageWithRenderingMode:image.renderingMode]; 124 | return flippedImage; 125 | } 126 | 127 | @implementation UIImage (MaterialRTL) 128 | 129 | - (UIImage *)mdf_imageWithHorizontallyFlippedOrientation { 130 | // On iOS 10 and above, UIImage supports the imageWithHorizontallyFlippedOrientation method. 131 | // Otherwise, we manually manipulate the image. 132 | if ([self respondsToSelector:@selector(imageWithHorizontallyFlippedOrientation)]) { 133 | //TODO: (#22) Replace with @availability when we adopt Xcode 9 as our minimum supported version. 134 | #pragma clang diagnostic push 135 | #pragma clang diagnostic ignored "-Wpartial-availability" 136 | return [self imageWithHorizontallyFlippedOrientation]; 137 | #pragma clang diagnostic pop 138 | } else { 139 | UIImage *mirroredImage; 140 | UIImageOrientation mirroredOrientation = MDFRTLMirroredOrientation(self.imageOrientation); 141 | if (self.CGImage) { 142 | CGImageRef _Nonnull image = (CGImageRef _Nonnull)self.CGImage; 143 | mirroredImage = [[self class] imageWithCGImage:image 144 | scale:self.scale 145 | orientation:mirroredOrientation]; 146 | } else if (self.CIImage) { 147 | CIImage * _Nonnull image = (CIImage * _Nonnull)self.CIImage; 148 | mirroredImage = [[self class] imageWithCIImage:image 149 | scale:self.scale 150 | orientation:mirroredOrientation]; 151 | } 152 | 153 | // If we were unsuccessful, manually flip the image using a Core Graphics context 154 | if (!mirroredImage) { 155 | mirroredImage = MDFRTLFlippedImage(self); 156 | } 157 | 158 | // On iOS9- [UIImage imageWithCGImage:scale:orientation:] loses the rendering mode. 159 | // Restore it if the new renderingMode does not match the current renderingMode. 160 | if (mirroredImage.renderingMode != self.renderingMode) { 161 | mirroredImage = [mirroredImage imageWithRenderingMode:self.renderingMode]; 162 | } 163 | 164 | return mirroredImage; 165 | } 166 | } 167 | 168 | @end 169 | -------------------------------------------------------------------------------- /Sources/UIView+MaterialRTL.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | /** 20 | Complete backporting of iOS 9's `-[UIView semanticContentAttribute]` and 21 | `+[UIView userInterfaceLayoutDirectionForSemanticContentAttribute:]`, and iOS 10's 22 | `-[UIView effectiveUserInterfaceLayoutDirection]` and 23 | `+[UIView userInterfaceLayoutDirectionForSemanticContentAttribute:relativeToLayoutDirection:]`. 24 | */ 25 | 26 | 27 | 28 | @interface UIView (MaterialRTL) 29 | 30 | // UISemanticContentAttribute was added in iOS SDK 9.0 but is available on devices running earlier 31 | // version of iOS. We ignore the partial-availability warning that gets thrown on our use of this 32 | // symbol. 33 | #pragma clang diagnostic push 34 | #pragma clang diagnostic ignored "-Wpartial-availability" 35 | 36 | /** 37 | Returns the layout direction implied by the provided semantic content attribute relative to the 38 | application-wide layout direction (as returned by 39 | UIApplication.sharedApplication.userInterfaceLayoutDirection). However, if it's being called from 40 | an iOS 8 extension, it will return left-to-right every time. 41 | 42 | @param semanticContentAttribute The semantic content attribute. 43 | @return The layout direction. 44 | */ 45 | + (UIUserInterfaceLayoutDirection)mdf_userInterfaceLayoutDirectionForSemanticContentAttribute: 46 | (UISemanticContentAttribute)semanticContentAttribute; 47 | 48 | /** 49 | Returns the layout direction implied by the provided semantic content attribute relative to the 50 | provided layout direction. For example, when provided a layout direction of 51 | RightToLeft and a semantic content attribute of Playback, this method returns LeftToRight. Layout 52 | and drawing code can use this method to determine how to arrange elements, but might find it easier 53 | to query the container view's mdf_effectiveUserInterfaceLayoutDirection property instead. 54 | 55 | @param semanticContentAttribute The semantic content attribute. 56 | @param layoutDirection The layout direction to consider. 57 | @return The implied layout direction. 58 | */ 59 | + (UIUserInterfaceLayoutDirection) 60 | mdf_userInterfaceLayoutDirectionForSemanticContentAttribute: 61 | (UISemanticContentAttribute)semanticContentAttribute 62 | relativeToLayoutDirection: 63 | (UIUserInterfaceLayoutDirection)layoutDirection; 64 | 65 | #pragma clang diagnostic pop 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Sources/UIView+MaterialRTL.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "UIView+MaterialRTL.h" 18 | 19 | #import 20 | 21 | #define MDF_BASE_SDK_EQUAL_OR_ABOVE(x) \ 22 | (defined(__IPHONE_##x) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_##x)) 23 | 24 | // UISemanticContentAttribute was added in iOS SDK 9.0 but is available on devices running earlier 25 | // version of iOS. We ignore the partial-availability warning that gets thrown on our use of this 26 | // symbol. 27 | #pragma clang diagnostic push 28 | #pragma clang diagnostic ignored "-Wpartial-availability" 29 | 30 | static inline UIUserInterfaceLayoutDirection 31 | MDFUserInterfaceLayoutDirectionForSemanticContentAttributeRelativeToLayoutDirection( 32 | UISemanticContentAttribute semanticContentAttribute, 33 | UIUserInterfaceLayoutDirection userInterfaceLayoutDirection) { 34 | switch (semanticContentAttribute) { 35 | case UISemanticContentAttributeUnspecified: 36 | return userInterfaceLayoutDirection; 37 | case UISemanticContentAttributePlayback: 38 | case UISemanticContentAttributeSpatial: 39 | case UISemanticContentAttributeForceLeftToRight: 40 | return UIUserInterfaceLayoutDirectionLeftToRight; 41 | case UISemanticContentAttributeForceRightToLeft: 42 | return UIUserInterfaceLayoutDirectionRightToLeft; 43 | } 44 | NSCAssert(NO, @"Invalid enumeration value %i.", (int)semanticContentAttribute); 45 | return userInterfaceLayoutDirection; 46 | } 47 | 48 | @interface UIView (MaterialRTLPrivate) 49 | 50 | // On iOS 9 and above, mdf_semanticContentAttribute is backed by UIKit's semanticContentAttribute. 51 | // On iOS 8 and below, mdf_semanticContentAttribute is backed by an associated object. 52 | @property(nonatomic, setter=mdf_setAssociatedSemanticContentAttribute:) 53 | UISemanticContentAttribute mdf_associatedSemanticContentAttribute; 54 | 55 | @end 56 | 57 | @implementation UIView (MaterialRTL) 58 | 59 | - (UISemanticContentAttribute)mdf_semanticContentAttribute { 60 | #if MDF_BASE_SDK_EQUAL_OR_ABOVE(9_0) 61 | if ([self respondsToSelector:@selector(semanticContentAttribute)]) { 62 | return self.semanticContentAttribute; 63 | } else 64 | #endif // MDF_BASE_SDK_EQUAL_OR_ABOVE(9_0) 65 | { 66 | return self.mdf_associatedSemanticContentAttribute; 67 | } 68 | } 69 | 70 | - (void)mdf_setSemanticContentAttribute:(UISemanticContentAttribute)semanticContentAttribute { 71 | #if MDF_BASE_SDK_EQUAL_OR_ABOVE(9_0) 72 | if ([self respondsToSelector:@selector(semanticContentAttribute)]) { 73 | self.semanticContentAttribute = semanticContentAttribute; 74 | } else 75 | #endif // MDF_BASE_SDK_EQUAL_OR_ABOVE(9_0) 76 | { 77 | self.mdf_associatedSemanticContentAttribute = semanticContentAttribute; 78 | } 79 | 80 | // Invalidate the layout. 81 | [self setNeedsLayout]; 82 | } 83 | 84 | + (UIUserInterfaceLayoutDirection)mdf_userInterfaceLayoutDirectionForSemanticContentAttribute: 85 | (UISemanticContentAttribute)attribute { 86 | #if MDF_BASE_SDK_EQUAL_OR_ABOVE(9_0) 87 | if ([self 88 | respondsToSelector:@selector(userInterfaceLayoutDirectionForSemanticContentAttribute:)]) { 89 | return [self userInterfaceLayoutDirectionForSemanticContentAttribute:attribute]; 90 | } else 91 | #endif // MDF_BASE_SDK_EQUAL_OR_ABOVE(9_0) 92 | { 93 | // If we are running in the context of an app, we query [UIApplication sharedApplication]. 94 | // Otherwise use a default of Left-to-Right. 95 | UIUserInterfaceLayoutDirection applicationLayoutDirection = 96 | UIUserInterfaceLayoutDirectionLeftToRight; 97 | NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; 98 | // Can I use kAppBundleIdentifier ? 99 | if ([bundlePath hasSuffix:@".app"]) { 100 | // We can't call sharedApplication directly or an error gets thrown for app extensions. 101 | UIApplication *application = 102 | [[UIApplication class] performSelector:@selector(sharedApplication)]; 103 | applicationLayoutDirection = application.userInterfaceLayoutDirection; 104 | } 105 | return [self 106 | mdf_userInterfaceLayoutDirectionForSemanticContentAttribute:attribute 107 | relativeToLayoutDirection:applicationLayoutDirection]; 108 | } 109 | } 110 | 111 | + (UIUserInterfaceLayoutDirection) 112 | mdf_userInterfaceLayoutDirectionForSemanticContentAttribute: 113 | (UISemanticContentAttribute)semanticContentAttribute 114 | relativeToLayoutDirection: 115 | (UIUserInterfaceLayoutDirection)layoutDirection { 116 | #if MDF_BASE_SDK_EQUAL_OR_ABOVE(10_0) 117 | if ([self 118 | respondsToSelector:@selector(userInterfaceLayoutDirectionForSemanticContentAttribute: 119 | relativeToLayoutDirection:)]) { 120 | return [self userInterfaceLayoutDirectionForSemanticContentAttribute:semanticContentAttribute 121 | relativeToLayoutDirection:layoutDirection]; 122 | } else { 123 | return MDFUserInterfaceLayoutDirectionForSemanticContentAttributeRelativeToLayoutDirection( 124 | semanticContentAttribute, layoutDirection); 125 | } 126 | #else 127 | return MDFUserInterfaceLayoutDirectionForSemanticContentAttributeRelativeToLayoutDirection( 128 | semanticContentAttribute, layoutDirection); 129 | #endif // MDF_BASE_SDK_EQUAL_OR_ABOVE(10_0) 130 | } 131 | 132 | @end 133 | 134 | @implementation UIView (MaterialRTLPrivate) 135 | 136 | - (UISemanticContentAttribute)mdf_associatedSemanticContentAttribute { 137 | NSNumber *semanticContentAttributeNumber = 138 | objc_getAssociatedObject(self, @selector(mdf_semanticContentAttribute)); 139 | if (semanticContentAttributeNumber != nil) { 140 | return [semanticContentAttributeNumber integerValue]; 141 | } 142 | return UISemanticContentAttributeUnspecified; 143 | } 144 | 145 | - (void)mdf_setAssociatedSemanticContentAttribute: 146 | (UISemanticContentAttribute)semanticContentAttribute { 147 | objc_setAssociatedObject(self, @selector(mdf_semanticContentAttribute), 148 | @(semanticContentAttribute), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 149 | } 150 | 151 | @end 152 | 153 | #pragma clang diagnostic pop 154 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/MDFBidiTests.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2018-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "MDFInternationalization.h" 20 | 21 | @interface MDFBidiTests : XCTestCase 22 | 23 | @end 24 | 25 | @implementation MDFBidiTests 26 | 27 | - (void)setUp { 28 | [super setUp]; 29 | // Put setup code here. This method is called before the invocation of each test method in the class. 30 | } 31 | 32 | - (void)tearDown { 33 | // Put teardown code here. This method is called after the invocation of each test method in the class. 34 | [super tearDown]; 35 | } 36 | 37 | - (void)testUniqueLocaleDirectionality { 38 | BOOL isLTR = [NSLocale mdf_isDefaultLanguageLTR]; 39 | BOOL isRTL = [NSLocale mdf_isDefaultLanguageRTL]; 40 | 41 | XCTAssertTrue(isLTR != isRTL, @"Locale cannot be LTR and RTL at the same time"); 42 | } 43 | 44 | - (void)testLTRStringDirection { 45 | NSString *testString = @"The quick brown fox jumps over the lazy dog."; 46 | NSLocaleLanguageDirection MDFResult = [testString mdf_calculatedLanguageDirection]; 47 | XCTAssertEqual(MDFResult, NSLocaleLanguageDirectionLeftToRight); 48 | } 49 | 50 | - (void)testPersoArabicRTLStringDirection { 51 | NSString *testString = @"الثعلب البني السريع يقفز فوق الكلب الكسول"; 52 | NSLocaleLanguageDirection MDFResult = [testString mdf_calculatedLanguageDirection]; 53 | XCTAssertEqual(MDFResult, NSLocaleLanguageDirectionRightToLeft); 54 | } 55 | 56 | - (void)testHebrewRTLStringDirection { 57 | NSString *testString = @"12 ספרים"; 58 | NSLocaleLanguageDirection MDFResult = [testString mdf_calculatedLanguageDirection]; 59 | XCTAssertEqual(MDFResult, NSLocaleLanguageDirectionRightToLeft); 60 | } 61 | 62 | - (void)testAddLTRMarkers { 63 | NSString *testString = @"quick brown fox"; 64 | NSString *wrappedString = 65 | [testString mdf_stringWithBidiEmbedding:NSLocaleLanguageDirectionLeftToRight]; 66 | XCTAssertTrue([wrappedString isEqualToString:@"\u202aquick brown fox\u202c"]); 67 | } 68 | 69 | - (void)testAddRTLMarkers { 70 | NSString *testString = @"quick brown fox"; 71 | NSString *wrappedString = 72 | [testString mdf_stringWithBidiEmbedding:NSLocaleLanguageDirectionRightToLeft]; 73 | XCTAssertTrue([wrappedString isEqualToString:@"\u202bquick brown fox\u202c"]); 74 | } 75 | 76 | - (void)testAddCalculatedMarkers { 77 | NSString *testString = @"The quick brown fox jumps over the lazy dog."; 78 | NSString *wrappedString = 79 | [testString mdf_stringWithBidiEmbedding]; 80 | XCTAssertTrue([wrappedString isEqualToString:@"\u202aThe quick brown fox jumps over the lazy dog.\u202c"]); 81 | } 82 | 83 | - (void)testStripMarkers { 84 | NSString *testString = @"\u202aThe quick brown fox jumps over the lazy dog.\u202c"; 85 | NSString *strippedString = [testString mdf_stringWithBidiMarkersStripped]; 86 | XCTAssertTrue([strippedString isEqualToString:@"The quick brown fox jumps over the lazy dog."]); 87 | } 88 | 89 | - (void)testLTRStereoIsolateLTR { 90 | NSString *testString = @"The quick brown fox jumps over the lazy dog."; 91 | NSLocaleLanguageDirection stringDirection = NSLocaleLanguageDirectionLeftToRight; 92 | NSLocaleLanguageDirection contextDirection = NSLocaleLanguageDirectionLeftToRight; 93 | 94 | NSString *wrappedString = 95 | [testString mdf_stringWithStereoReset:stringDirection 96 | context:contextDirection]; 97 | 98 | // ??? Since the context is the same as the string, do we need the markers 99 | XCTAssertTrue([wrappedString isEqualToString:@"\u202aThe quick brown fox jumps over the lazy dog.\u202c"]); 100 | } 101 | 102 | - (void)testLTRStereoIsolateRTL { 103 | NSString *testString = @"The quick brown fox jumps over the lazy dog."; 104 | NSLocaleLanguageDirection stringDirection = NSLocaleLanguageDirectionLeftToRight; 105 | NSLocaleLanguageDirection contextDirection = NSLocaleLanguageDirectionRightToLeft; 106 | 107 | NSString *wrappedString = 108 | [testString mdf_stringWithStereoReset:stringDirection 109 | context:contextDirection]; 110 | 111 | // !!! wrappedString is "\u202b\u202aThe quick brown fox jumps over the lazy dog.\u202c\u202c 112 | // ??? Since the context is the same as the string, do we need the markers 113 | XCTAssertTrue([wrappedString isEqualToString:@"\u200f\u202aThe quick brown fox jumps over the lazy dog.\u202c\u200f"]); 114 | } 115 | 116 | - (void)testRTLStereoIsolateRTL { 117 | NSString *testString = @"The quick brown fox jumps over the lazy dog."; 118 | NSLocaleLanguageDirection stringDirection = NSLocaleLanguageDirectionRightToLeft; 119 | NSLocaleLanguageDirection contextDirection = NSLocaleLanguageDirectionRightToLeft; 120 | 121 | NSString *wrappedString = 122 | [testString mdf_stringWithStereoReset:stringDirection 123 | context:contextDirection]; 124 | 125 | // !!! wrappedString is "\u202b\u202aThe quick brown fox jumps over the lazy dog.\u202c\u202c 126 | // ??? Since the context is the same as the string, do we need the markers 127 | XCTAssertTrue([wrappedString isEqualToString:@"\u202bThe quick brown fox jumps over the lazy dog.\u202c"]); 128 | } 129 | 130 | // Simple Tests 131 | 132 | - (void)testSimpleLanguageDirectionOfPunctuationString { 133 | NSString *testString = @"@#%+=-^*"; 134 | 135 | // Then 136 | XCTAssertEqual([testString mdf_calculatedLanguageDirection], NSLocaleLanguageDirectionLeftToRight); 137 | } 138 | 139 | - (void)testSimpleLanguageDirectionOfNumericString { 140 | NSString *testString = @"123"; 141 | 142 | // Then 143 | XCTAssertEqual([testString mdf_calculatedLanguageDirection], NSLocaleLanguageDirectionLeftToRight); 144 | } 145 | 146 | - (void)testSimpleLanguageDirectionOfHebrewString { 147 | NSString *testString = @"!שלום"; 148 | 149 | // Then 150 | XCTAssertEqual([testString mdf_calculatedLanguageDirection], NSLocaleLanguageDirectionRightToLeft); 151 | } 152 | 153 | - (void)testSimpleLanguageDirectionOfEnglishString { 154 | NSString *testString = @"Hello!"; 155 | 156 | // Then 157 | XCTAssertEqual([testString mdf_calculatedLanguageDirection], NSLocaleLanguageDirectionLeftToRight); 158 | } 159 | 160 | - (void)testSimpleLanguageDirectionOfEmptyString { 161 | NSString *testString = @""; 162 | 163 | // Then 164 | XCTAssertEqual([testString mdf_calculatedLanguageDirection], NSLocaleLanguageDirectionLeftToRight); 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /Tests/MDFInternationalizationTests.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | //FIXME: Remove this file if there are no tests 20 | 21 | @interface MDFInternationalizationTests : XCTestCase 22 | 23 | @end 24 | 25 | @implementation MDFInternationalizationTests 26 | 27 | - (void)setUp { 28 | [super setUp]; 29 | // Put setup code here. This method is called before the invocation of each test method in the class. 30 | } 31 | 32 | - (void)tearDown { 33 | // Put teardown code here. This method is called after the invocation of each test method in the class. 34 | [super tearDown]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Tests/MDFRTLTests.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016-present Google Inc. All Rights Reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "MDFInternationalization.h" 20 | 21 | @interface RTLTests : XCTestCase 22 | 23 | @end 24 | 25 | @implementation RTLTests 26 | 27 | - (void)setUp { 28 | [super setUp]; 29 | // Put setup code here. This method is called before the invocation of each test method in the class. 30 | } 31 | 32 | - (void)tearDown { 33 | // Put teardown code here. This method is called after the invocation of each test method in the class. 34 | [super tearDown]; 35 | } 36 | 37 | - (void)testMDCRectHorizontallyFlipped { 38 | CGRect frame = CGRectMake(10.0, 20.0, 50.0, 30.0); 39 | CGRect flippedFrame = MDFRectFlippedHorizontally(frame, 100.0); 40 | CGRect validResultFrame = CGRectMake(40.0, 20.0, 50.0, 30.0); 41 | 42 | XCTAssert(CGRectEqualToRect(flippedFrame, validResultFrame)); 43 | } 44 | 45 | - (void)testMDCRectDoublyHorizontallyFlipped { 46 | CGRect frame = CGRectMake(10.0, 20.0, 50.0, 30.0); 47 | CGRect flippedFrame = MDFRectFlippedHorizontally(frame, 100.0); 48 | CGRect twiceFlippedFrame = MDFRectFlippedHorizontally(flippedFrame, 100.0); 49 | 50 | XCTAssert(CGRectEqualToRect(frame, twiceFlippedFrame)); 51 | } 52 | 53 | - (void)testNegativeMDCRectHorizontallyFlipped { 54 | CGRect frame = CGRectMake(60.0, 50.0, -50.0, -30.0); 55 | CGRect flippedFrame = MDFRectFlippedHorizontally(frame, 100.0); 56 | CGRect validResultFrame = CGRectMake(40.0, 20.0, 50.0, 30.0); 57 | 58 | XCTAssert(CGRectEqualToRect(flippedFrame, validResultFrame)); 59 | } 60 | 61 | - (void)testMDCRectFlippedForRTLRightToLeft { 62 | CGRect frame = CGRectMake(10.0, 20.0, 50.0, 30.0); 63 | CGFloat boundsWidth = 100.0; 64 | CGRect flippedFrame = MDFRectFlippedHorizontally(frame, boundsWidth); 65 | CGRect validResultFrame = CGRectMake(40.0, 20.0, 50.0, 30.0); 66 | 67 | XCTAssert(CGRectEqualToRect(flippedFrame, validResultFrame)); 68 | } 69 | 70 | - (void)testMDCRectFlippedForRTLNegativeRightToLeft { 71 | CGRect frame = CGRectMake(60.0, 50.0, -50.0, -30.0); 72 | CGFloat boundsWidth = 100.0; 73 | CGRect flippedFrame = MDFRectFlippedHorizontally(frame, boundsWidth); 74 | CGRect validResultFrame = CGRectMake(40.0, 20.0, 50.0, 30.0); 75 | 76 | XCTAssert(CGRectEqualToRect(flippedFrame, validResultFrame)); 77 | } 78 | 79 | - (void)testMDCInsetsMakeWithLayoutDirectionLeftToRight { 80 | UIEdgeInsets insets = MDFInsetsMakeWithLayoutDirection(10, 20, 30, 40, UIUserInterfaceLayoutDirectionLeftToRight); 81 | XCTAssertEqual(insets.left, 20); 82 | XCTAssertEqual(insets.right, 40); 83 | } 84 | 85 | - (void)testMDCInsetsMakeWithLayoutDirectionRightToLeft { 86 | UIEdgeInsets insets = MDFInsetsMakeWithLayoutDirection(10, 20, 30, 40, UIUserInterfaceLayoutDirectionRightToLeft); 87 | XCTAssertEqual(insets.left, 40); 88 | XCTAssertEqual(insets.right, 20); 89 | } 90 | 91 | - (void)testMDCRTLFlippedImagePortsRenderingMode { 92 | UIImage *image = [RTLTests standardImage]; 93 | UIImage *flippedImage = [image mdf_imageWithHorizontallyFlippedOrientation]; 94 | 95 | XCTAssertTrue(image.renderingMode == UIImageRenderingModeAutomatic); 96 | XCTAssertTrue(flippedImage.renderingMode == UIImageRenderingModeAutomatic); 97 | 98 | UIImage *templateImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 99 | UIImage *flippedTemplateImage = [templateImage mdf_imageWithHorizontallyFlippedOrientation]; 100 | 101 | XCTAssertTrue(templateImage.renderingMode == UIImageRenderingModeAlwaysTemplate); 102 | XCTAssertTrue(flippedTemplateImage.renderingMode == UIImageRenderingModeAlwaysTemplate); 103 | 104 | UIImage *originalImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 105 | UIImage *flippedOriginalImage = [originalImage mdf_imageWithHorizontallyFlippedOrientation]; 106 | 107 | XCTAssertTrue(originalImage.renderingMode == UIImageRenderingModeAlwaysOriginal); 108 | XCTAssertTrue(flippedOriginalImage.renderingMode == UIImageRenderingModeAlwaysOriginal); 109 | } 110 | 111 | //TODO: (#6) Implement per-pixel comparison 112 | //- (void)testImageMirror { 113 | // UIImage *sourceImage = [RTLTests standardImage]; 114 | // UIImage *flippedImage = [sourceImage mdf_imageWithHorizontallyFlippedOrientation]; 115 | // UIImage *twiceFlippedImage = [flippedImage mdf_imageWithHorizontallyFlippedOrientation]; 116 | 117 | // sourceImage != flippedImage 118 | // sourceImage == twiceFlippedImage 119 | //} 120 | 121 | 122 | // Pixel Image is a 1 x 1 red square 123 | + (UIImage *)pixelImage { 124 | CGRect frame = CGRectMake(0.0, 0.0, 1.0, 1.0); 125 | 126 | UIGraphicsBeginImageContext(frame.size); 127 | 128 | CGContextRef context = UIGraphicsGetCurrentContext(); 129 | 130 | CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor); 131 | CGContextFillRect(context, frame); 132 | 133 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 134 | UIGraphicsEndImageContext(); 135 | 136 | return image; 137 | } 138 | 139 | // Standard Image is a blue rectangle with a green line from top left to bottom right 140 | + (UIImage *)standardImage { 141 | static UIImage *image; 142 | static dispatch_once_t onceToken; 143 | dispatch_once(&onceToken, ^{ 144 | CGRect frame = CGRectMake(0.0, 0.0, 60.0, 40.0); 145 | 146 | UIGraphicsBeginImageContext(frame.size); 147 | 148 | CGContextRef context = UIGraphicsGetCurrentContext(); 149 | 150 | CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor); 151 | CGContextFillRect(context, frame); 152 | 153 | CGContextSetStrokeColorWithColor(context, [UIColor greenColor].CGColor); 154 | CGContextSetLineWidth(context, 1.0); 155 | 156 | CGContextMoveToPoint(context, 0.0, 0.0); 157 | CGContextAddLineToPoint(context, 60.0, 40.0); 158 | 159 | CGContextStrokePath(context); 160 | 161 | image = UIGraphicsGetImageFromCurrentImageContext(); 162 | UIGraphicsEndImageContext(); 163 | }); 164 | 165 | return image; 166 | } 167 | 168 | @end 169 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | # Copyright 2017-present The Material Foundation Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 16 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") 17 | 18 | git_repository( 19 | name = "build_bazel_rules_apple", 20 | remote = "https://github.com/bazelbuild/rules_apple.git", 21 | commit = "19f031f09185e0fcd722c22e596d09bd6fff7944", # 0.19.0 22 | shallow_since = "1570721035 -0700", # 10-10-2019 23 | ) 24 | 25 | load( 26 | "@build_bazel_rules_apple//apple:repositories.bzl", 27 | "apple_rules_dependencies", 28 | ) 29 | 30 | apple_rules_dependencies() 31 | 32 | load( 33 | "@build_bazel_rules_swift//swift:repositories.bzl", 34 | "swift_rules_dependencies", 35 | ) 36 | 37 | swift_rules_dependencies() 38 | 39 | load( 40 | "@build_bazel_apple_support//lib:repositories.bzl", 41 | "apple_support_dependencies", 42 | ) 43 | 44 | apple_support_dependencies() 45 | 46 | git_repository( 47 | name = "bazel_ios_warnings", 48 | remote = "https://github.com/material-foundation/bazel_ios_warnings.git", 49 | commit = "c3f720c0838af1ee53299aa6efda87cf729146b4", # v3.0.0 50 | shallow_since = "1545400728 -0500" # 12-21-2018 51 | ) 52 | -------------------------------------------------------------------------------- /apple_framework_relative_headers.bzl: -------------------------------------------------------------------------------- 1 | """Bazel rules for supporting framework-relative header imports.""" 2 | 3 | load( 4 | "@build_bazel_rules_apple//apple/internal:file_support.bzl", 5 | "file_support", 6 | ) 7 | 8 | def _apple_framework_relative_headers_impl(ctx): 9 | """Implementation for apple_framework_relative_headers rule.""" 10 | output_dir = ctx.attr.framework_name + "_apple_framework_relative_headers" 11 | 12 | outputs = [] 13 | for f in ctx.files.hdrs: 14 | framework_path = "/".join([output_dir, ctx.attr.framework_name, f.basename]) 15 | framework_header_file = ctx.actions.declare_file(framework_path) 16 | file_support.symlink(ctx, f, framework_header_file) 17 | outputs.append(framework_header_file) 18 | 19 | # Documentation of these implicit types can be found here: 20 | # ctx: https://docs.bazel.build/versions/master/skylark/lib/ctx.html 21 | # ctx.label: https://docs.bazel.build/versions/master/skylark/lib/Label.html 22 | 23 | include_dir = "/".join([ 24 | ctx.configuration.bin_dir.path, ctx.label.workspace_root, ctx.label.package, output_dir]) 25 | return [ 26 | apple_common.new_objc_provider( 27 | header=depset(outputs), 28 | include=depset([include_dir]), 29 | ), 30 | DefaultInfo(files=depset(outputs)), 31 | ] 32 | 33 | 34 | apple_framework_relative_headers = rule( 35 | _apple_framework_relative_headers_impl, 36 | attrs = { 37 | "hdrs": attr.label_list(allow_files=[".h"], allow_empty=False), 38 | "framework_name": attr.string(mandatory=True), 39 | "_realpath": attr.label( 40 | cfg="host", 41 | allow_single_file=True, 42 | default=Label("@bazel_tools//tools/objc:realpath"), 43 | ), 44 | }, 45 | ) 46 | """Creates a directory structure suitable for framework-relative import 47 | statements. 48 | 49 | For example, one would be able to #import given the following rules: 50 | 51 | apple_framework_relative_headers( 52 | name = "FooFrameworkHeaders", 53 | hdrs = ["Source/Bar.h"], 54 | framework_name = "Foo", 55 | ) 56 | 57 | objc_library( 58 | ... 59 | deps = [":FooFrameworkHeaders"], 60 | ) 61 | 62 | Args: 63 | hdrs: The list of header files. 64 | framework_name: The name of the framework. 65 | """ 66 | --------------------------------------------------------------------------------