Localization Project

e.g. google Product team
– develop
– introduce new features
– introduce new versions

-> google localization team
-> localization production, language services, vendor management, localization operations
Localization Project Manager(LPM)
-> external localization company: language service provider(LSP)
Language managers(Spanish, Hindi, Traditional Chinese)
Lastly product team launch service globally

Localization operations
– technology, business
Vendor Management finds LSPs, builds relationships

-Requesters, localization project managers, language mangers, localization operations, vendor mangement, external language service providers

User Interface

User Interface:
The space where interactions between humans and machines occur.

e.g. ATM
Withdraw, Deposit, Manage Accounts, Account Blance

Desktop software: applications you download and install onto laptop or desktop computers
Web apps: Similar to desktop applications, but they run on mobile phones and have different considerations
Mobile apps: Similar to traditional software, to use them, you don’t need to install

Where?
UI is found on desktop, web and on the phone.
Who?
UI is used by new users as well as users familiar with the product.
Why?
UI enable users to accomplish goals.
-> lack of product knowledge
Providing message descriptions, Providing Reference material and guidelines

Research what people search in local.
Telefoni Cellulari, Cellulari

English, Turkish, Turkish back translation
hotel chain, otel zinciri, hotel chain
holidays, tail, holiday vacation
hospitality, misavirperverlik, generosity
istanbul hotels, istanbul otelleri, istanbul hotels

localization

In house: engineers, translation team, project manager

Marketing Content: Engaging, Persuasive, Well Written
– First contact with a product
– Used by anyone interested in the product
– Designed to attract potential users

Online help
– FAQS
– Software Documentation
– Troubleshooting Manuals

Product knowledge, Consistent Terminology

Where?
videos are in online help pages, marketing pages, training platforms etc.

Revoicing
voice-over, dubbing, narration, audio description, free commentary

Dubbing:Actors’ voices are recorded over the original audio track
Subtitling:Written translation of spoken words and on-screen text

Nullability Annotations

_Nullable -can have a nil value
-Nonnull -not expected to be nil

@interface Book : NSObject

@property (nonatomic, copy) NSString *title;
@property (nonatomic) Person *author;
@property (nonatomic) Person *editor;
@property (nonatomic) int yearOfPublication;

-(instancetype)initWithTitle:(NSString*)title
	author:(Person*)author
	year:(int)year;

@end

Code for the NSCoding Protocol

class Gif: NSObject, NSCoding {
	let url: NSURL
	let videoURL: NSURL
	let caption: String?
	let gitImage: UIImage
	var gifData: NSData?

	init(url: NSURL, videoURL: NSURL, caption: String?){
		self.url = url
		self.videoURL = videoURL
		self.caption = caption
		self.gifImage = UIImage.gifWithURL(url.absoluteString)!
		self.gifData = nil
	}

	required init?(coder decoder: NSCoder){
		self.url = decoder.decodeObjectForKey("url") as! NSURL
		self.videoURL = decoder.decodeObjectForKey("videoURL") as! NSURL
		self.caption = decoder.decodeObjectForKey("caption") as? String
		self.gifImage = decoder.decodeObjectForKey("gifImage") as! UIImage
		self.gifData = decoder.decodeObjectForKey("gifData") as? NSData
	}

	func encodeWithCoder(coder: NSCoder){
		coder.encodeObject(self.url, forKey: "url")
		coder.encodeObject(self.videoURL, forKey: "videoURL")
		coder.encodeObject(self.caption, forKey: "caption")
		coder.encodeObject(self.gifImage, forKey: "gifImage")
		coder.encodeObject(self.gifData, forKey:"gifData")
	}
}

create the file path

var gifsFilePath: String {
	let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
	let documentsPath = directories[0]
	let gifsPath = documentsPath.stringByAppendingString("/savedGifs")
	return gifsPath
}
var gif: Gif?
@IBOutlet weakl var gifImageView: UIImageView!

override func viewDidLoad(){
	super.viewDidLoad()
	gifImageView.image = gif?.gifImage
}

@IBAction func sharedGif(sendr: UIButton){
	var itemsToShare = [NSData]()
	itemsToShare.append((self.gif?gifData)!)

	let activityVC = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil)
	activityVC.completionWithItemsHandler = {(activity, comleted, items, error) in:
		if (completed){
			self.dismissViewControllerAnimated(true, completion: nil)
		}
	}
	presentViewController(activityVC, animated: true, completion:nil)
}

Enable Video Trimming

imagePicker property settings

func imagePicker(source:UIImagePickerControllerSourceType) -> UIImagePickerController {
	let picker = UIImagePickerController()
	picker.sourceType = source;
	picker.mediaTypes = [kUTTypeMovie as String]
	picker.allowsEditing = true;
	picker.delegate = self;

	return picker
}
func imagePicker(source:UIImagePickerControllerSourceType) -> UIImagePickerController {
	let picker = UIImagePickerController()
	picker.sourceType = source;
	picker.mediaTypes = [kUTTypeMovie as String]
	picker.allowsEditing = true;
	picker.delegate = self;

	return picker	
}

func convertVideToGIF(videoURL: NSURL, start: NSNumber?, duration: NSNumber?){
	dispatch_async(dispatch_get_main_queue()){
		self.dismissViewControllerAnimated(true, completion: nil)
	}

	let regift: Regift;

	if let start = start {
		regift = Regift(sourceFileURL: videoURL, destinationFileURL: nil, startTime: start.floatValue, duration: duration!.floatValue, frameRate: frameRate, loopCount: loopCount)
	} else {
		// Untrimmed
		regift = Regift(sourceFileURL: videoURL, destinationFileURL: nil, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount)
	}

	let gifURL = regif.createGif()
	let gif = Gif(url: gifURL!, rawVideoURL: videoURL, caption: nil)
	displayGIF(gif)
}

public func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo
	info: [String : AnyObject]){
	let mediaType = info[UIImagePickerControllerMediaType] as! String

	if mediaType == kUTTypeMovie as String {

		let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
		let start: NSNumber? = info["_UIImagePickerControllerVideoEditingStart"] as? NSNumber
		let end: NSNumber? = info["_UIImagePickerControllerVideoEditingEnd"] as? NSNumber	
		var duration: NSNumber?
		if let start = start {
			duration = NSNumber(float: (end!.floatValue) - (start.floatValue))
		} else {
			duration = nil
		}
		convertVideoToGIF(videoURL, start: start, duration: duration)
	}	
}

Make room for keyboard

// Methods to adjust the keyboard
extension GiftEditorViewController {
	func subscribeToKeyboardNotifications(){
		NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GiftEditorViewController.keyboardWillShow(_:)),
			name: UIKeyboardWillShowNotification,
			object: nil)
		NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GiftEditorViewController.keyboardWillHide(_:)),
			name: UIKeyboardWillHideNotification,
			object: nil)

	}

	func unsubscribeFromKeyboardNotifications(){
		NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
		NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
	}

	func keyboardWillShow(notification: NSNotification){
		if view.frame.origin.y >= 0 {
			view.frame.origin.y -= getKeyboardHeight(notification)
		}
	}

	func getKeyboardHeight(notification: NSNotification) -> CGFloat{
		let userInfo = notification.userInfo
		let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
		return keyboardSize.CGRectValue().height
	}
}

Share the GIF

@IBAction func shareGif(sender: AnyObject){
	let url: NSURL = (self.gif?.url)!
	let animatedGIF = NSData(contentsOfURL: url)!
	let itemsToShare = [animatedGIF]

	let activityVC = UIActivityViewController(activityItems: itemToShare, applicationActivities: nil)

	activityVC.completionWithItemsHandler = {(activity, completed, items, error) in
		if(completed){
			self.navigationController?.popToRootViewControllerAnimated(true)
		}
	}

	navigationController?.presentViewController(activityVC, animated: true, completion: nil)
}

Create an Action Sheet

@IBAction func presentVideoOptions(){
	if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
		//launchPhotoLibrary()
	} else {

		let newGifActionSheet = UIAlertController(title: "Create new GIF", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)

		let recordVideo = UIAlertAction(title: "Record a Video", style: UIAlertActionStyle.Default, handler: {
			(UIAlertAction) in self.launchVideoCamera()
			})
	}
}

Gif class

class Gif {
	let url: NSURL
	let videoURL: NSURL
	let caption: String?
	let gifImage: UIImage?
	var gifData: NSData?

	init(url:NSURL, videoURL: NSURL, caption: String?){

		self.url = url
		self.videoURL = videoURL
		self.caption = caption
		self.gifImage = UIImage.gifWithURL(url.absoluteString)!
		self.gifData = nil
	}

	init(name: String){
		self.gifImage = UIImage.gifWithName(name)
	}
}
#import <UIKit/UIKit.h>
#import "Gif.h"

@interface GifEditorViewController : UIViewController<UITextFeildDelegate>

@property (nonatomic) Gif *gif;
@property (weak, nonatomic) IBOutlet UIImageView *gifImageView;

@end

UITextFieldDelegate Methods

func textFieldDidBeginEditing(textField: UITextField){
	textField.placeholder = ""
}

func textFieldShoudReturn(textField: UITextField) -> Bool {
	textField.resignFirstResponder()
	return true
}

Implement Regift Methods

import Foundation
import UIKit
import MobileCoreServices

// Regift constants
let frameCount = 16
let delayTime: Float = 0.2
let loopCount = 0 // 0 means loop forever

extension UIViewController: UIImagePickerDelegate, UINavigationControllerDelegate {
	
	@IBAction func launchVideoCamera(sender: AnyObject){
		let recordVideoController = UIImagePickerController()
		recordVideoController.sourceType = UIImagePickerControllerSourceType.launchVideoCamera
		recordVideoController.mediaTypes = [kUTTypeMovie as String]
		recordVideoController.allowsEditing = false
		recordVideoController.delegate = self

		presentViewController(recordVideoController, animated: true, completion: nil)
	}
	public func imagePickereController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
		let mediaType = info[UIImagePickerControllerMediaType] as! String

		if mediaType == kUTTypeMovie as String {
			let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
			dismissViewControllerAnimated(true, completion: nil)
			UISaveVideoAtPathToSavedPhotosAlbum(videoURL.path!, nil, nil, nil)
		}
	}

	public func imagePickerControllerDidCancel(picker: UIImagePickerController){
		dismissViewControllerAnimated(true, completion: nil)
	}

	func convertVideoToGIF(videoURL: NSURL){
		let regift = Regift(sourceFileURL: videoURL, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount)
	}
}
#import <UIKit/UIKit.h>
#import "Gif.h"

@interface GifEditorViewController : UIViewController<UITextFiledDelegate>

@property (nonatomic) Gif *gif;
@property (weak, nonatomic) IBOutlet UIImageView *gifImageView;

@end

Rewriting the Gif Class

@interface Gif : NSObject <NSCoding>

@property (nonatomic) NSURL *url;
@property (nonatomic) NSString *caption;
@property (nonatomic) UIImage *gifImage;
@property (nonatomic) NSURL *videoURL;
@property (nonatomic) NSData *gifData;

-(instancetype)initWithGifUrl: (NSURL*)url videoURL:(NSURL*)videoURL caption:(NSString*)caption;
-(instancetype)initWithName:(NSString*)name;
@end

UIViewController Extension

// Mark: -UIViewController: UINavigationControllerDelegate

extension UIViewController: UINavigationControllerDelegate {}

// Mark: -UIViewController: UIImagePickerControllerDelegate

extension UIViewController: UIImagePickerControllerDelegate {
	
	public func imagePickerController(picker: UIImagePickerController,
		didFinishPickingMediaWithInfo info: [String : AnyObject]){
		let mediaType = info[UIImagePickerControllerMediaType] as! String

		if mediaType == kUTTypeMovie as String {
			let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
		}
	}

	public func imagePickerControllerDidCancel(picker: UIImagePickerController){
		dismissViewControllerAnimated(true, completion: nil)
	}
}

Display a GIF in a UIImage

#import "WelcomViewController.h"
#import "UIViewController+Record.h"

@interface WelcomeviewController()

@property (nonatomic) NSURL *squareURL;

@end

@implementation WelcomeviewController

- (void)viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];

	Gif *firstLaunchGif = [[Gif alloc] initWithName:@"tinaFeyHiFive"];
	self.defaultGifImageView.image = firstLaunchGif.gifImage;

	[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WelcomeViewSeen"];
}

@end

WelcomeViewController

import UIKit

class WelcomViewController: UIViewController {
	
	@IBOutlet weak var gifImageView: UIImageView!

	override func viewWillAppear(animated: Bool){
		// Return an animated UIImage
	}

	override func viewDidLoad(){
		super.viewDidLoad()

		// Do any additional setup after loading the view.
	}

	override func didReceiveMemoryWarning(){
		super.didReceiveMemoryWarning()
		// Dispose of any resources that can be recreated.
	}
}